Java 确定ExceptionHandler中可接受的内容类型

Java 确定ExceptionHandler中可接受的内容类型,java,spring,spring-mvc,spring-boot,Java,Spring,Spring Mvc,Spring Boot,在Spring应用程序中,我有一个通常返回图像的端点(products=MediaType.image\u PNG\u VALUE) 我还有@ExceptionHandler函数来处理各种函数 我正在试图找到一种方法,从@ExceptionHandler中确定客户端是否接受text/plain或text/json,以便在发生错误时,我可以返回其中一个,或者如果他们只希望image/png,则可以忽略它 如何确定可以为给定请求返回哪些可接受的内容类型?您可以访问请求以检查标题并返回适当的响应。这是

在Spring应用程序中,我有一个通常返回图像的端点(
products=MediaType.image\u PNG\u VALUE

我还有
@ExceptionHandler
函数来处理各种函数

我正在试图找到一种方法,从
@ExceptionHandler
中确定客户端是否接受
text/plain
text/json
,以便在发生错误时,我可以返回其中一个,或者如果他们只希望
image/png
,则可以忽略它


如何确定可以为给定请求返回哪些可接受的内容类型?

您可以访问请求以检查标题并返回适当的响应。这是标准的

下面是一个例子:

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = {RuntimeException.class})
    protected ResponseEntity<Object> handleMyException(RuntimeException ex, WebRequest request) {
        List<String> acceptableMimeTypes = Arrays.asList(request.getHeaderValues(HttpHeaders.ACCEPT));
        if (acceptableMimeTypes.contains(MediaType.TEXT_PLAIN_VALUE)) {
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
                    .body("hello");
        }
        throw ex;
    }
}
@ControllerAdvice
公共类MyExceptionHandler扩展了ResponseEntityExceptionHandler{
@ExceptionHandler(值={RuntimeException.class})
受保护的ResponseEntity handleMyException(RuntimeException ex,WebRequest请求){
List-acceptableMimeTypes=Arrays.asList(request.getHeaderValues(HttpHeaders.ACCEPT));
if(acceptablemmetypes.contains(MediaType.TEXT\u PLAIN\u VALUE)){
返回ResponseEntity.ok()
.header(HttpHeaders.CONTENT\u类型、MediaType.TEXT\u普通值)
.body(“你好”);
}
掷骰子;
}
}
有一些参数
spring mvc
可以自动注入
controller
方法,而
WebRequest
(即
spring
http
请求的表示)就是其中之一。如果客户端发送了一个带有请求的
Accept:text/plain
头,那么上面的示例将返回字符串
hello
,如果存在
RuntimeException
。如果没有异常,则根本不会触发此逻辑,因此端点将只返回它通常返回的任何内容。您可以阅读有关
@ControllerAdvice
@ExceptionHandler
的更多信息


当然,一定要考虑要处理的确切异常类型,以及要返回的语义上合适的状态代码,以便客户端知道如何正确解释响应。

这就是我想到的答案。它与YoungSpice的类似,但更灵活,直接使用MediaType(这意味着它将处理通配符类型,如
text/*
等):

private ResponseEntity buildResponse(WebRequest请求、HttpStatus状态、字符串消息){
HttpHeaders httpHeader=新的HttpHeaders();
列表接受头=
parseMediaTypes(Arrays.asList(request.getHeaderValues(HttpHeaders.ACCEPT));
if(acceptHeader.stream().anyMatch(mediaType->mediaType.isCompatibleWith(mediaType.APPLICATION_JSON))){
httpHeader.setContentType(MediaType.APPLICATION_JSON);
返回新的响应属性(“{\”错误\“:\”+消息+“\”}”,httpHeader,状态);
}else if(acceptHeader.stream().anyMatch(mediaType->mediaType.isCompatibleWith(mediaType.TEXT\u PLAIN))){
httpHeader.setContentType(MediaType.TEXT\u PLAIN);
返回新的响应属性(消息、httpHeader、状态);
}否则{
返回ResponseEntity.status(status).body(null);
}
}
基本上,它使用
MediaType.parseMediaTypes()
来解析
Accept
头,然后我对它们进行流式处理,并使用
MediaType.isCompatibleWith()
函数来检查我的目标是否可接受。这将允许它处理头中类似于
application/*
的内容,而不是直接使用
application/json


另外,如果请求中没有明确提供
Accept
,则会出现一个隐含的
*/*
,它似乎按预期工作。

对于下一个投票人,是否愿意分享原因?我问了一个很狭隘的问题。我可以提供一些示例代码,但它不会给问题添加任何内容,至于我的实际问题,我不知道从哪里开始。我可能只需要一两行。
private ResponseEntity<String> buildResponse(WebRequest request, HttpStatus status, String message) {
        HttpHeaders httpHeader = new HttpHeaders();
        List<MediaType> acceptHeader =
                MediaType.parseMediaTypes(Arrays.asList(request.getHeaderValues(HttpHeaders.ACCEPT)));

        if (acceptHeader.stream().anyMatch(mediaType -> mediaType.isCompatibleWith(MediaType.APPLICATION_JSON))) {
            httpHeader.setContentType(MediaType.APPLICATION_JSON);
            return new ResponseEntity<>("{ \"error\": \"" + message + "\" }", httpHeader, status);
        } else if (acceptHeader.stream().anyMatch(mediaType -> mediaType.isCompatibleWith(MediaType.TEXT_PLAIN))) {
            httpHeader.setContentType(MediaType.TEXT_PLAIN);
            return new ResponseEntity<>(message, httpHeader, status);
        } else {
            return ResponseEntity.status(status).body(null);
        }
    }