【发布时间】:2021-03-24 12:20:48
【问题描述】:
使用 Java 11,Springt Boot WebClient
创建了一个 REST Web 服务(服务 1),它尝试使用一个 REST Web 服务(服务 2),该服务预计会返回 JSON,该 JSON 将映射到我的自定义响应对象。但是由于要消费的服务(Service 2)目前不在线,我会收到 404 not found。
问题似乎是 404 响应以 'text/html;charset=iso-8859-1' 的形式出现,无法映射到我的 DocumentResponse 对象。
Webclient 配置为接受 xml 和 json。
如何拦截和处理这些 http 状态响应而不会出现此异常。
通常我会通过在我的请求链上使用 .block() 来接收响应,并为正在使用该响应的服务 1 创建适当的响应。
例如:
Documentresponse response = invoiceDeliveryControllerApi.deliverInvoiceUsingPOST(request,"test").block();
public Mono<Documentresponse> deliverInvoiceUsingPOST(Documentrequest request, String name) throws WebClientResponseException {
Object postBody = request;
// verify the required parameter 'request' is set
if (request == null) {
throw new WebClientResponseException("Missing the required parameter 'request' when calling deliverInvoiceUsingPOST", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), null, null, null);
}
// create path and map variables
final Map<String, Object> pathParams = new HashMap<String, Object>();
final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
final HttpHeaders headerParams = new HttpHeaders();
final MultiValueMap<String, String> cookieParams = new LinkedMultiValueMap<String, String>();
final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();
queryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", name));
final String[] localVarAccepts = {
"application/xml", "text/xml"
};
final List<MediaType> localVarAccept = apiClient.selectHeaderAccept(localVarAccepts);
final String[] localVarContentTypes = {
"application/xml", "text/xml"
};
final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes);
String[] localVarAuthNames = new String[] { };
ParameterizedTypeReference<Documentresponse> localVarReturnType = new ParameterizedTypeReference<Documentresponse>() {};
return apiClient.invokeAPI("/api/v1/deliverinvoice", HttpMethod.POST, pathParams, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType);
}
public <T> Mono<T> invokeAPI(String path, HttpMethod method, Map<String, Object> pathParams, MultiValueMap<String, String> queryParams, Object body, HttpHeaders headerParams, MultiValueMap<String, String> cookieParams, MultiValueMap<String, Object> formParams, List<MediaType> accept, MediaType contentType, String[] authNames, ParameterizedTypeReference<T> returnType) throws RestClientException {
final WebClient.RequestBodySpec requestBuilder = prepareRequest(path, method, pathParams, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames);
return requestBuilder.retrieve().bodyToMono(returnType);
}
public static WebClient buildWebClient(ObjectMapper mapper) {
ExchangeStrategies strategies = ExchangeStrategies
.builder()
.codecs(clientDefaultCodecsConfigurer -> {
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(mapper, MediaType.APPLICATION_JSON));
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(mapper, MediaType.APPLICATION_JSON));
}).build();
WebClient.Builder webClient = WebClient.builder().filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(logRequest());
exchangeFilterFunctions.add(logResponse());
}).exchangeStrategies(strategies);
return webClient.build();
}
现在我想找到一种方法来响应这些 html 响应并为服务 1 创建一个响应,这会告诉用户在调用服务 2 时出现 http 连接错误
有什么建议吗?
PS:客户端代码是使用 openapi 代码生成器生成的,并针对日志记录进行了略微调整。
编辑:我发现通常它就像在 .block() 捕获 WebClientException 一样简单,并且使用状态码我可以生成令人满意的响应消息。
但我发现一个奇怪的行为是,如果 Service 2 的响应是 f.e. 400 Bad Request 它以 text/html 形式交付,没有添加 charset=iso-8859-1。
在这种情况下,它会导致预期的 WebClientResponseException。但是对于 404 not found text/html charset=iso-8859-1 的实例被传递并导致 UnexpectedMediaTypeException。有没有办法解释原因?
让我更困惑的是,在预期的 404 的情况下,我通过 WebClientFilters 的日志记录提供状态 307 重定向(到我首先调用的相同 url)和 302 找到 text/html charset=iso-8859- 1 也会导致 MediaTypeException。虽然通过 Postman 使用完全相同的数据进行的同一呼叫提供 404。有人知道发生了什么吗?
【问题讨论】:
标签: java spring-boot spring-webclient