java - 当 HTTP 请求返回状态 401 时,如何在 Java 中解析响应正文

标签 java spring api jackson resttemplate

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

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

我们需要解析body,并在我们的业务逻辑中使用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 block 中出现 HttpMessageNotReadableException:

"Could not read JSON: cannot retry due to server authentication, in streaming mode"

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

restTemplate.postForObject(url, pojoInstance, responseClass);

如果使用普通的旧客户端程序(如 Postman)执行相同的请求,则会收到预期的 JSON 响应。因此,我认为问题可能出在 Spring 的 ClientHttpResponse 实现以某种方式不允许访问响应正文,以防 401 状态。

真的可以解析响应体吗?

更新

根据我的调查,RestTemplate 类使用 ClientHttpResponse 反过来创建 sun.net.www.protocol.http.HttpURLConnection提供输入流。它在那里,输入流被忽略并抛出 IOException:

cannot retry due to server authentication, in streaming mode

所以,HttpURLConnection 的实现导致了这个问题。

是否有可能避免这个问题?也许我们应该使用一种替代实现,在出现错误状态代码的情况下不忽略响应主体?你能推荐任何替代品吗?

最佳答案

在不需要自定义处理程序的情况下尝试以下方法。这个想法是从 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());

关于java - 当 HTTP 请求返回状态 401 时,如何在 Java 中解析响应正文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26676405/

相关文章:

database - 如何在 Julia 中管理凭据?

java - 如何使用 MiGLayout 将组件居中放置在包含多个组件的行上

java - 每次我编辑 Java 文件的最细微部分时,Tomcat 都会自动重新启动。我怎样才能阻止它?

java - 在测试中模拟一个 Logger 类

java - 基于谁是被调用者的逻辑

javascript - Microsoft QnA Maker API 错误未找到资源

java - 无法将 int 字段设置为空值

java - 在静态创建者方法后面隐藏构造函数?

java - java中的中断线程

javascript - 如何从客户端安全地发送密码?