当前位置: 首页 > 知识库问答 >
问题:

当HTTP请求具有返回状态401时,如何在Java中解析响应主体

裘兴思
2023-03-14

我正在使用Spring的RestTemplate和Jackson使用一个RESTful JSON API。在某些情况下,我们可能会收到带有自定义JSON主体的状态401(未经授权)响应,该主体由API制造商定义,如下所示:

{
    "code": 123,
    "message": "Reason for the error"
}

我们需要解析主体,并在业务逻辑中使用code属性。

这是我们需要解析的错误响应Java对象:

public class CustomError {

    @JsonProperty
    private Integer code;
    @JsonProperty
    private String message;

    public Integer getCode() {
       return code;
    }
    public String getMessage() {
        return message;
    }
}

以及一个自定义错误处理程序来执行此操作:

public class CustomErrorHandler extends DefaultResponseErrorHandler {
    private RestTemplate restTemplate;
    private ObjectMapper objectMapper;
    private MappingJacksonHttpMessageConverter messageConverter;


    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return super.hasError(response);
    }

    @Override
    public void handleError(final ClientHttpResponse response) throws IOException {

        try {
            CustomError error = 
                (CustomError) messageConverter.read(CustomError.class, response);
            throw new CustomErrorIOException(error, error.getMessage());
        } catch (Exception e) {
            // parsing failed, resort to default behavior
            super.handleError(response);
        }
    }
}

错误处理程序失败,在try块中出现了一个httpmessagenoteradableexception

无法读取JSON:由于服务器身份验证,在流模式下无法重试

这就是我发送请求的方式:

restTemplate.postForObject(url, pojoInstance, responseClass);

如果使用普通的旧rest客户端程序(如Postman)执行相同的请求,则会收到预期的JSON响应。因此,我假设问题可能是Spring的ClientHttpResponse实现在401状态的情况下不允许访问响应体。

真的有可能解析响应体吗?

最新消息

从我所调查的,RestTemboard类使用ClientHttpContent,这反过来又创建了一个提供输入流的sun.net.www.protocol.http.HttpURLConnection。在那里,输入流被忽略,并抛出一个IOExc0019

无法重试由于服务器身份验证,在流模式

因此,HttpURLConnection的实现导致了这个问题。

有可能避免这个问题吗?也许我们应该使用另一种实现,在出现错误状态代码时不会忽略响应体?你能推荐其他选择吗?

共有3个答案

乐正浩博
2023-03-14

我只在mapper上使用了clientHttpResponse<代码>ClientHttpResponse。getBody()是与HttpStatusCodeException类似的流。getResponseBodyAsString。

@Component
public class xhandler extends RestTemplateErrorHandler{


    @Override
    protected boolean handleServiceSpecificError(ClientHttpResponse response) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            CustomError error =mapper.readValue(response.getBody(), CustomError.class);
            throw new RestClientException(“x Service returned an error response with error-code: "+response.getStatusCode().toString() + error.getErrorMessage());
        } catch (IOException e) {
            LOG.error(create(this.getClass(), "002"), “x Service returned an error, but the error response could not be parsed: {}", e.toString(), e);
        }
        return false;
    }

}
胡和煦
2023-03-14

我是这样做的:

@Component
public class RestTemplateFactory {
public enum Type {
    JSON, XML
}

public RestTemplate create(Type type) {
    RestTemplate restTemplate = new RestTemplate();
    if (type == Type.XML) {
        Jaxb2RootElementHttpMessageConverter jaxbMessageConverter = new Jaxb2RootElementHttpMessageConverter();
        jaxbMessageConverter.setSupportedMediaTypes(Lists.newArrayList(MediaType.TEXT_HTML, MediaType.APPLICATION_XML));
        restTemplate.setMessageConverters(Lists.newArrayList(jaxbMessageConverter));
    }
    restTemplate.setErrorHandler(new BpmRestErrorHandler(restTemplate.getMessageConverters()));
    return restTemplate;
}

public HttpHeaders contentHeaders(Type type) {
    HttpHeaders headers = new HttpHeaders();
    if (type == Type.XML) {
        headers.setContentType(MediaType.APPLICATION_XML);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_XML));
    } else {
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
    }
    return HttpHeaders.readOnlyHttpHeaders(headers);
}
}

和handler:

public class BpmRestErrorHandler extends DefaultResponseErrorHandler {

private final List<HttpMessageConverter<?>> messageConverters;

public BpmRestErrorHandler(List<HttpMessageConverter<?>> messageConverters) {
    this.messageConverters = messageConverters;
}

@Override
public void handleError(ClientHttpResponse response) throws IOException {
    for (HttpMessageConverter messageConverter : messageConverters) {
        if (messageConverter.canRead(RestRuntimeException.class, response.getHeaders().getContentType())) {
            RestRuntimeExceptionData exceptionData =
                    (RestRuntimeExceptionData)messageConverter.read(RestRuntimeException.class, response);
            throw new BpmRestException(exceptionData);
        }
    }
    super.handleError(response);
}
}

其中,RestRuntimeExceptionData是我的自定义WebFault对象。它重新使用了RestTemplate的HttpConverters。

穆德海
2023-03-14

在不需要自定义处理程序的情况下尝试以下方法。其思想是从HttpStatusCodeException获取字符串形式的响应,然后将其转换为对象。对于转换,我使用了Jackson的ObjectMapper:

        try {

            restTemplate.postForObject(url, pojoInstance, responseClass);

        } catch (HttpStatusCodeException e) {

            if (e.getStatusCode() == HttpStatus.UNAUTHORIZED) {

                String responseString = e.getResponseBodyAsString();

                ObjectMapper mapper = new ObjectMapper();

                CustomError result = mapper.readValue(responseString,
                        CustomError.class);
            }
        }

更新:使用不同的工厂也可能有所帮助,因为默认工厂中有一个与您的问题相关的错误(见下面的评论):

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
 类似资料:
  • 问题内容: 我正在使用Spring 和Jackson 的RESTful JSON API 。在某些情况下,我们可能会收到带有自定义JSON主体的(未经授权)响应,该响应由API制造商定义,如下所示: 我们需要解析主体,并在业务逻辑中使用该属性。 这是我们需要解析为的错误响应Java对象: 还有一个自定义错误处理程序可以做到这一点: 错误处理程序失败,并在try块中显示: “无法读取JSON:由于服

  • 下面是我正在使用的一段代码: 期望reponse conatins的状态行:“HTTP/1.1400坏请求”想知道这是可以实现的吗?如果是,那么我如何继续做同样的事情。

  • 所有人。我是Angular 2和Spring框架的新手。我正在尝试一个带有授权头(基本身份验证)的简单get请求。 我使用的是Spring Boot(1.2.6.Release),这也可能是相关的。我的CORS配置如下所示。 帮帮我,我不知道我错过了什么...我已经查了很多帖子,但都没找到。

  • 我使用curl获取http头以查找http状态代码并返回响应。我使用以下命令获取http头

  • 我想用响应替换http异常,也就是说,我使用我想返回的responseentity,例如409如果没有通过名称找到用户,509如果没有通过邮件找到用户,我可以确定responseentity中的错误号及其描述吗?如果有,可以举例说明吗?

  • 问题内容: 大家。我是Angular 2和Spring框架的新手。我正在尝试使用授权标头(基本auth)进行简单的get请求。 我正在使用Spring Boot(1.2.6.RELEASE),这也可能是相关的。我的CORS配置如下所示。 这是客户端的外观 我不断得到: XMLHttpRequest无法加载 http:// localhost:8080 / api / login?username