簡體   English   中英

org.springframework.web.reactive.function.UnsupportedMediaTypeException:內容類型'text/html;charset = iso-8859-1'不支持bodyType =

[英]org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'text/html;charset=iso-8859-1' not supported for bodyType=

使用 Java 11、Springt Boot WebClient

Created a REST Webservice(Service 1) which tries to consume a REST WebService(Service 2) which is expected to return JSON which would be mapped to my custom response object. 但是由於要消費的服務(服務 2)目前不在線,我會收到 404 not found。

問題似乎是 404 響應以 'text/html;charset=iso-8859-1' 的形式出現,並且無法映射到我的 DocumentResponse Object 上。

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 一樣簡單,並且使用狀態代碼我可以生成令人滿意的響應消息。

但我發現一個奇怪的行為是,如果服務 2 的響應是 fe 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。有人知道發生了什么嗎?

來自WebBlient#bodyToMono java 文檔:

Extract the body to a {@code Mono}. By default, if the response has status code 4xx or 5xx, the {@code Mono} will contain a {@link WebClientException}. This can be overridden with {@link #onStatus(Predicate, Function)}.

根據狀態碼實現錯誤處理:

requestBuilder
            .retrieve()
            .onStatus(HttpStatus::is4xxClientError, res -> Mono<? extends Throwable>)
            .onStatus(HttpStatus::is5xxServerError, res -> Mono<? extends Throwable>)
            .bodyToMono(responseType)
            .onErrorResume(Status400Throwable.class, th -> Mono.just(fallbackResponseHere)) 
            .onErrorResume(Status500Throwable.class, th -> Mono.just(fallbackResponseHere));

如果您不希望默認錯誤處理程序返回WebClientResponseException ,請查看WebClient.ResponseSpec#onStatus java 文檔以及Mono#onErrorResume之類的內容。

回答我自己的問題:

the strange behaviour of the client giving me UnsupportedMediaTypeException in case of expected 404 status code, was somehow caused by a redirect 307 followed by 302 found wich was caused by me using http url instead of https url.

我不知道為什么它只是 404 狀態碼的情況。 但是在將 baseURI 更改為 https 后,我不再收到重定向或不支持的 MediaTypeExceptions,而是收到預期的 WEbClientResponseExceptions。

現在我將嘗試使用 Serg Vasylchak 的答案來處理錯誤而不捕獲異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM