Spring @ExceptionHandler 返回 HTTP 406

Dan*_*ski 5 java rest spring exception-handling spring-mvc

我有一些奇怪的错误。

我想要做什么: 客户端询问 GET: /invoices/invoiceNumber with header Accept: application/pdf 并且我想返回 PDF 文件。如果客户端忘记了标头,我将返回 HTTP 406。

返回 PDF 字节的方法抛出由 Spring ExceptionHandler 处理的 DocumentNotFoundException 并且应该返回 404,但它没有。取而代之的是,我有 406 和服务器日志:

 2017-06-01 15:14:03.844  WARN 2272 --- [qtp245298614-13] o.e.jetty.server.handler.ErrorHandler    : Error page loop /error
Run Code Online (Sandbox Code Playgroud)

当 Spring Security 返回 HTTP 401 时会发生同样的魔法。

所以我认为这个问题是 Client Acceptapplication/pdf但 Spring ExceptionHandler 返回application/json,所以码头调度程序用 406 覆盖 404 :(

我的代码:

@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Invoice not found")
@ExceptionHandler(DocumentNotFoundException.class)
public void handleException() {
    //impl not needed
}

@GetMapping(value = "invoices/**", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> getInvoicePdf(HttpServletRequest request) {
    String invoiceNumber = extractInvoiceNumber(request);
    final byte[] invoicePdf = invoiceService.getInvoicePdf(invoiceNumber);
    return new ResponseEntity<>(invoicePdf, buildPdfFileHeader(invoiceNumber), HttpStatus.OK);

}

@GetMapping(value = "invoices/**")
public ResponseEntity getInvoiceOther() {
    return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
}
Run Code Online (Sandbox Code Playgroud)

有人可以帮助我理解吗?

小智 2

问题是 Spring 尝试将错误响应转换为 PDF application/pdf,但未能找到合适的HttpMessageConverter支持转换为 PDF 的文件。

最简单的解决方案是手动创建错误响应:

@ExceptionHandler(DocumentNotFoundException.class)
public ResponseEntity<?> handleException(DocumentNotFoundException e) {

    return ResponseEntity
        .status(HttpStatus.NOT_FOUND)
        .contentType(MediaType.APPLICATION_JSON_UTF8)
        .body("{\"error\": \"Invoice not found\"}");
}
Run Code Online (Sandbox Code Playgroud)

这会绕过消息转换并产生 HTTP 404 响应代码。