java - Spring Web客户端返回异常“bodyType = [responseObject]不支持内容类型'application / json'
问题描述
我使用 Web 客户端发布第三方 API,第三方 API 返回响应如下:
{
"RetailTransactionGenericResponse": {
"authID": 1146185,
"product": {
"amount": 20,
"balance": 0,
"status": "D",
"metafields": {
"metafield": [
{
"name": "serialNum",
"value": 8095843490
}
]
}
},
"responseCode": 0,
"responseText": "Success",
"transactionID": "b0924cca-f2a9-477f-915b-9153e74ebce0"
}
}
所以在我的payload
包中,它有RetailTransactionGenericResponseWrapper
类,其中包含RetailTransactionGenericResponse
类。
这是RetailTransactionGenericResponse
类的代码
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
@Builder
@AllArgsConstructor(onConstructor_ = @JsonCreator)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RetailTransactionGenericResponse {
@JsonProperty
private String authID;
@JsonProperty
private Product product;
@JsonProperty
private String responseCode;
@JsonProperty
private String responseText;
@JsonProperty
private String transactionID;
}
上课Product
用
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Product {
@JsonProperty
@JsonInclude(JsonInclude.Include.NON_NULL)
private double amount;
@JsonProperty
@JsonInclude(JsonInclude.Include.NON_NULL)
private String code;
@JsonProperty
@JsonInclude(JsonInclude.Include.NON_NULL)
private String upc;
// Response part
@JsonProperty
@JsonInclude(JsonInclude.Include.NON_NULL)
private MetaFields metafields;
@JsonProperty
@JsonInclude(JsonInclude.Include.NON_NULL)
private String balance;
@JsonProperty
@JsonInclude(JsonInclude.Include.NON_NULL)
private String status;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this, ToStringStyle.JSON_STYLE);
}
}
和MetaFields
上课
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MetaFields {
@JsonProperty
private List<MetaField> metafield;
}
和MetaField
类
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MetaField {
@JsonProperty
private String name;
@JsonProperty
private String value;
}
因此,在我的服务中,这是我尝试检索响应的方式
RetailTransactionGenericResponseWrapper response =
webClient.post().uri(url).headers(headers -> headers.setBearerAuth(token)).accept(APPLICATION_JSON)
.body(Mono.just(retailTransactionGenericRequest), RetailTransactionGenericResponseWrapper.class)
.retrieve().bodyToMono(RetailTransactionGenericResponseWrapper.class).block();
我做错了什么,它无法将 json 映射到对象?
这是异常堆栈
ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from POST https://[third_party_url]; nested exception is org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/json' not supported for bodyType=com.xxx.xxx.payload.xxx.RetailTransactionGenericResponseWrapper] with root cause
org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/json' not supported for bodyType=com.xxx.xxx.payload.xxx.RetailTransactionGenericResponseWrapper
at org.springframework.web.reactive.function.BodyExtractors.lambda$readWithMessageReaders$12(BodyExtractors.java:201)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ Body from POST https://[third_party_url] [DefaultClientResponse]
Stack trace:
at org.springframework.web.reactive.function.BodyExtractors.lambda$readWithMessageReaders$12(BodyExtractors.java:201)
at java.base/java.util.Optional.orElseGet(Optional.java:369)
at org.springframework.web.reactive.function.BodyExtractors.readWithMessageReaders(BodyExtractors.java:197)
at org.springframework.web.reactive.function.BodyExtractors.lambda$toMono$2(BodyExtractors.java:85)
at org.springframework.web.reactive.function.client.DefaultClientResponse.body(DefaultClientResponse.java:132)
at org.springframework.web.reactive.function.client.DefaultClientResponse.bodyToMono(DefaultClientResponse.java:147)
at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultResponseSpec.lambda$bodyToMono$2(DefaultWebClient.java:541)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:73)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:120)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199)
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2346)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onSubscribeInner(MonoFlatMapMany.java:150)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:189)
at reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:99)
at reactor.core.publisher.FluxRetryWhen$RetryWhenMainSubscriber.onNext(FluxRetryWhen.java:173)
at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:160)
at reactor.netty.http.client.HttpClientConnect$HttpIOHandlerObserver.onStateChange(HttpClientConnect.java:389)
at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:612)
at reactor.netty.resources.DefaultPooledConnectionProvider$DisposableAcquire.onStateChange(DefaultPooledConnectionProvider.java:195)
at reactor.netty.resources.DefaultPooledConnectionProvider$PooledConnection.onStateChange(DefaultPooledConnectionProvider.java:466)
at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:613)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:94)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:311)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:432)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1533)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1282)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1329)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
根据尼古拉的评论,我尝试关注...
RetailTransactionGenericResponseWrapper response =
webClient.post().uri(url).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.headers(headers -> {
headers.setBearerAuth(token);
}).accept(APPLICATION_JSON)
.body(Mono.just(retailTransactionGenericRequest), RetailTransactionGenericResponseWrapper.class)
.retrieve().bodyToMono(RetailTransactionGenericResponseWrapper.class).block();
像这样
RetailTransactionGenericResponseWrapper response = webClient.post().uri(url).headers(headers -> {
headers.setBearerAuth(token);
headers.setContentType(APPLICATION_JSON);
}).contentType(APPLICATION_JSON).accept(APPLICATION_JSON)
.body(Mono.just(retailTransactionGenericRequest), RetailTransactionGenericResponseWrapper.class).retrieve()
.bodyToMono(RetailTransactionGenericResponseWrapper.class).block();
我仍然得到相同的异常堆栈
解决方案
将以下标头添加到您的 WebClient 请求
webClient
//...
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
//...
没有那个杰克逊的 JSON 编解码器没有注册为身体提取器候选者。如果您不指定“Content-Type”标头,默认情况下它将是“application/octet-stream”,Jackson 不支持。
推荐阅读
- excel - 代码不会确认奇数,不会将它们放在 B 列中
- bash - bash 中的陷阱执行顺序
- java - 如何为 RCP 产品创建安装程序/.exe/.msi?
- vim - 运行时如何在 Windows gVim 中保留当前工作目录!命令或 system() 函数
- python - Python,为什么我的for循环应该创建两个docx文件?
- tensorflow - 在 TensorFlow 中提取层的输出
- excel - 要堆叠的自定义加载项工具栏
- sql-server - 使用 sp_rename 动态更改 SQL Server 中的多个表名
- c - 同时使用 rand() 和 rand_r() :这个简单的例子正确吗?
- bash - 怎么修 ”
: hGetLine: end of file" 在 docker-compose 命令中运行 stack build --file-watch 时