错误响应中的REST-API不同内容类型

Vha*_*aos 6 java api rest json spring-mvc

几个星期以来,我正在使用spring-mvc进行休息api.REST-API工作正常,在涉及到特定错误对象的错误处理时,我几乎完成了直到最后一个问题.

REST-API使用JSON作为格式来序列化Java对象.在服务执行期间发生错误时,会创建特定的错误对象并将其发送回客户端.

当我的休息服务标记为"produce = application/json"时,一切正常.但是也有一些服务只需要使用"produce = text/plain"返回简单文本.当其中一个服务发生错误时,Spring-MVC将抛出HttpMediaTypeNotAcceptableException.似乎是正确的,因为客户端要求内容类型为"text/plain",而服务器响应为"application/json".

你能告诉我这个问题的正确解决方案是什么吗?

  1. 仅使用JSON作为响应内容类型并将简单文本包装在特殊的类对象中.=>对我来说似乎不是真的REST,因为REST应该支持多种内容类型.

  2. 每个服务"text"的服务都将标记为"produce = application/json; text/plain",而Client也需要在"accept-header"中发送两者.=>这样做时,API似乎支持相同资源的两种内容类型.但那不对.只有在出现错误的情况下,API才会返回JSON,否则它将始终为"text".

听起来像一个非常特殊的REST问题,并且无法找到关于这个主题的相关问题.

nim*_*mai 5

我遇到了同样的问题,我对 REST 最佳实践也有完全相同的问题。

我读到的所有关于处理 API 响应中的错误的文章都使用 JSON。示例 在这里

我不认为所有这些 API 总是将数据包装在 JSON 中。有时你只需要提供文件、文本或非 json 内容......此外,我偶然发现了RFC7807,它提出了一种标准方法来公开 JSON 格式的错误/问题,甚至使用它自己的内容类型应用程序/问题+json。因此,我们可以安全地假设对 HTTP 200 使用不同的内容类型而不是 HTTP 错误代码是一个很好的做法。

关于如何用Spring Framework来做,其实很简单。一旦您了解“produces ={}”基本上是一种声明性方式,表示您的响应将是某种类型,您可以想象也可以通过编程方式设置您想要返回的类型。

这是一个应返回 application/octet-stream(二进制文件)的示例 API。

@GetMapping(path = "/1/resources/hello", produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE})
public ResponseEntity<StreamingResponseBody> getFile(@RequestParam(value = "charset", required = false, defaultValue = "UTF-8") String charset) {
    return ResponseEntity.ok().body(outputStream -> outputStream.write("Hello there".getBytes(Charset.forName(charset))));
}
Run Code Online (Sandbox Code Playgroud)

当它工作时,它将返回一个具有正确内容类型的文件。现在,如果您想处理错误情况(在这种情况下是错误的字符集参数),您可以创建一个异常处理程序:

@ExceptionHandler(UnsupportedCharsetException.class)
public ResponseEntity<?> handleCharsetException(UnsupportedCharsetException e) {
    return ResponseEntity.badRequest().contentType(MediaType.APPLICATION_JSON_UTF8).body(new ErrorResponse("1", "Wrong charset"));
}
Run Code Online (Sandbox Code Playgroud)

现在,错误情况也按预期工作:

GET http://localhost/1/resources/hello?charset=CRAP

HTTP/1.1 400 Bad Request
Connection: keep-alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
Date: Mon, 25 Mar 2019 17:37:39 GMT

{
  "code": "1",
  "message": "Wrong charset"
}
Run Code Online (Sandbox Code Playgroud)


Opa*_*pal 4

用户应始终在标题中指定其期望的内容Accept。您的工作是按照标头中指定的格式返回在服务器端引发/捕获的错误Accept。据我所知,在春天,这可以通过特殊的映射器来实现。下面你可以找到用 groovy 编写的映射器来处理text/html

import groovy.xml.MarkupBuilder
import org.springframework.http.HttpInputMessage
import org.springframework.http.HttpOutputMessage
import org.springframework.http.converter.AbstractHttpMessageConverter

import static org.springframework.http.MediaType.TEXT_HTML

class ExceptionResponseHTMLConverter extends AbstractHttpMessageConverter<ExceptionResponse> {
  ExceptionResponseHTMLConverter() {
    super(TEXT_HTML)
  }

  @Override
  boolean supports(Class clazz) {
    clazz.equals(ExceptionResponse)
  }

  @Override
  ExceptionResponse readInternal(Class clazz, HttpInputMessage msg) {
    throw new UnsupportedOperationException()
  }

  @Override
  void writeInternal(ExceptionResponse e, HttpOutputMessage msg) {
    def sw = new StringWriter()
    new MarkupBuilder(sw).error {
      error(e.error)
      exception(e.exception)
      message(e.message)
      path(e.path)
      status(e.status)
      timestamp(e.timestamp)
    }
    msg.body << sw.toString().bytes
  }
}
Run Code Online (Sandbox Code Playgroud)

ExceptionResponse班级:

class ExceptionResponse {
  String error
  String exception
  String message
  String path
  Integer status
  Long timestamp
}
Run Code Online (Sandbox Code Playgroud)