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

HTTP 406的Spring return JSON(不可接受)

丁德义
2023-03-14

Spring允许在@Rest控件建议中定义@ExceptionHandler

我已经在那里为HTTP 400、404、405等定义了许多其他异常处理程序,。。。然而,HTTP 406的ExceptionHandler(不可接受)似乎不起作用。处理程序被触发,我在日志中对此进行了检查,但没有使用结果。

我的目标是返回一个带有JSON主体的HTTP 406。

变型1

@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ErrorDTO requestMethodNotSupported(final HttpMediaTypeNotAcceptableException e) {
    final ErrorDTO dto = new ErrorDTO(HttpStatus.NOT_ACCEPTABLE, "http.media_not_acceptable");
    return dto;
}

变体2

@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<ErrorDTO> requestMethodNotSupported2(final HttpMediaTypeNotAcceptableException e) {
    final ErrorDTO dto = new ErrorDTO(HttpStatus.NOT_ACCEPTABLE, "http.media_not_acceptable");
    return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).contentType(MediaType.APPLICATION_JSON_UTF8).body(dto);
}

但是我总是从Tomcat得到类似的超文本标记语言响应:

HTTP状态406-

类型:状态报告

消息:

描述:此请求标识的资源只能根据请求“accept”标头生成具有不可接受特征的响应。

而不是

{"errorCode": 406,"errorMessage":"http.media_not_acceptable"}

请求标头:

  • 接受:无法存在的应用程序/内容

实际响应标题:

  • 内容类型:text/html

预期的响应标头:

  • 内容类型:应用程序/json

我知道我可以简单地“修复”客户机发送的Accept头,但是如果服务器不知道如何响应,则应该始终使用JSON进行响应。

我使用Spring 4.3.3。RELEASE和Jackson 2.8.4。

共有2个答案

佴波鸿
2023-03-14

基于@ST-DDT调查结果。如果您也在扩展ResponseEntityExceptionHandler,那么您不能只添加另一个方法来处理HttpMediaTypeNotAcceptableException。然而,对于整个问题,还有一个更简单的解决方案:

    @Override
    public ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        ResponseEntity<Object> response = super.handleHttpMediaTypeNotAcceptable(ex, headers, status, request);

        // Workaround to return JSON response for 406
        return ResponseEntity.status(NOT_ACCEPTABLE)
                .contentType(APPLICATION_JSON)
                .body(response.getBody());
    }
劳仲渊
2023-03-14

最后,我找到了一个解决方案:

与其返回可序列化对象,不如直接返回字节。

private final ObjectMapper objectMapper = new ObjectMapper();

@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<byte[]> mediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException e) {
    Object response = ...;
    try {
        return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE)
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(objectMapper.writeValueAsBytes(response));
    } catch (Exception subException) {
        // Should never happen!!!
        subException.addSuppressed(e);
        throw subException;
    }
}

编辑:

作为替代方案,您可以创建一个自定义的HttpMessageConverter

  • 转到您的或创建一个impl的WebMvcConfigrerAdapter#extendMessageConverters(转换器)
  • 选择一个能够创建预期结果/内容类型的HttpMessageConverter
  • 以满足以下条件的方式包装它:
    • getSupport dMediaTypes()返回MediaType。ALL
    • canRead()返回false
    • canWrit()仅对您的错误响应
    • 返回true
    • write()设置强制CT并将您期望的内容类型转发到包装的转换器。
    • 如果添加为第一个元素,则它将始终返回您的预期结果(强制)
      • 请求:json,返回:强制CT
      • 请求:xml,返回:强制CT
      • 请求:图像,返回:强制CT
      • 请求:json,返回:json
      • 请求:xml,返回:xml
      • 请求:图像,返回:强制CT

 类似资料:
  • 我正在编写一个使用Java和Apache HttpClient的播客下载器。它适用于大多数RSS提要,但这一个失败了,出现了“406不可以接受”的错误。 链接是http://sqrpt.com/feed/podcast/

  • 我们的项目中有Spring-boot/hibernate/PostgreSQL应用程序,并使用Hikari作为连接池。我们不断遇到以下问题:几个小时后,活动连接数增长到极限,我们得到如下错误(完整堆栈跟踪位于问题的末尾): 以下是版本信息: JPA/Hibernate配置: HikariCP配置: 完整堆栈跟踪:

  • 问题内容: 我正在尝试生成一个简单的JSON响应。现在,我收到406 Not Acceptable错误。Tomcat说:“此请求标识的资源只能根据请求“接受”标头生成特性不可接受的响应。” 即使我的标题是 在tomcat / lib中,我拥有所有的Tomcat jar,Spring jar和jackson-all-1.9.0.jar。我在Tomcat 7中使用Spring 3.2.2。 我知道这个

  • 我正在尝试生成一个简单的JSON响应工作。现在我收到406不接受错误。Tomcat说“此请求标识的资源仅能够根据请求“接受”标头生成具有不可接受特征的响应。”即使我的标头是 在tomcat/lib中,我有所有的tomcat罐子、Spring罐子和jackson-all-1.9.0。罐子我将Spring 3.2.2用于Tomcat 7。 我知道这个问题已经讨论过很多次了,但是没有一个解决方案对我有用

  • 应用程序是使用Spring MVC 4、Hibernate和jQuery开发的 下面jquery AJAX调用没有给出正确的响应。。说明406错误(不可接受) 我知道这是一个非常古老而常见的问题。我尝试过: 杰克逊罐子 在请求映射注释中:生产者作为JSON 在请求映射注释中:标头为JSON 2和3的组合 $. post而不是$. ajax(我知道这没什么区别) 我的bean对象(Validatio