如何在 Spring Boot @ResponseBody 中返回 404 响应状态 - 方法返回类型是响应?

Posted

技术标签:

【中文标题】如何在 Spring Boot @ResponseBody 中返回 404 响应状态 - 方法返回类型是响应?【英文标题】:How to return 404 response status in Spring Boot @ResponseBody - method return type is Response? 【发布时间】:2014-10-14 20:18:28 【问题描述】:

我正在使用 Spring Boot 和基于 @ResponseBody 的方法,如下所示:

@RequestMapping(value = VIDEO_DATA_PATH, method = RequestMethod.GET)
public @ResponseBody Response getData(@PathVariable(ID_PARAMETER) long id, HttpServletResponse res) 
    Video video = null;
    Response response = null;
    video = videos.get(id - 1);
    if (video == null) 
      // TODO how to return 404 status
    
    serveSomeVideo(video, res);
    VideoSvcApi client =  new RestAdapter.Builder()
            .setEndpoint("http://localhost:8080").build().create(VideoSvcApi.class);
    response = client.getData(video.getId());
    return response;


public void serveSomeVideo(Video v, HttpServletResponse response) throws IOException  
    if (videoDataMgr == null) 
        videoDataMgr = VideoFileManager.get();
    
    response.addHeader("Content-Type", v.getContentType());
    videoDataMgr.copyVideoData(v, response.getOutputStream());
    response.setStatus(200);
    response.addHeader("Content-Type", v.getContentType());

我尝试了一些典型的方法:

res.setStatus(HttpStatus.NOT_FOUND.value()); 新的 ResponseEntity(HttpStatus.BAD_REQUEST);

但我需要返回Response。

如果视频为空,如何在这里返回 404 状态码?

【问题讨论】:

【参考方案1】:

这很简单,只需抛出 org.springframework.web.server.ResponseStatusException

throw new ResponseStatusException(
  HttpStatus.NOT_FOUND, "entity not found"
);

它与@ResponseBody 和任何返回值兼容。需要 Spring 5+

【讨论】:

有没有办法做到这一点而不导致 Springboot 发出警告?我得到`WARN 27604 --- [nio-8081-exec-9] .wsmaResponseStatusExceptionResolver : Resolved [org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND `,它不合理地进入警报等:这不是问题. @GreenAsJade 我不确定这个警告在哪里记录(我没有在我的日志中看到这个警告)但也许你可以使用 log4j 设置或与你的警报系统交谈来避免这种情况。跨度> 这不是最好的,您的访问者会看到错误堆栈信息。 @BuffK 这是用于网络服务(与机器对话) 这需要覆盖 /error 端点。【参考方案2】:

创建一个带有@ResponseStatus(HttpStatus.NOT_FOUND) 注释的NotFoundException 类并将其从控制器中抛出。

@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "video not found")
public class VideoNotFoundException extends RuntimeException 

【讨论】:

需要标准导入方式:import org.springframework.http.HttpStatus; @andrej 有时这是一个很好的解决方案,但是 (1) ResponseStatusException 直到 Spring 5 才添加; (2) NotFoundException 可用于被抓到或用于带有@ExceptionHandler 的双栈 html UI。 此解决方案将异常紧密耦合到您的 REST-Controller 层。我想避免的事情。我会在 @AroundAdvice 组件中使用 @ExceptionHandler 来代替 如果有人想使用 Spring 自带的预先存在的异常,org.springframework.data.rest.webmvc.ResourceNotFoundException 已经用 @ResponseStatus(HttpStatus.NOT_FOUND) 注释【参考方案3】:

您的原始方法可以返回 ResponseEntity(不会改变您的方法行为):

@RequestMapping(value = VIDEO_DATA_PATH, method = RequestMethod.GET)
public ResponseEntity getData(@PathVariable(ID_PARAMETER) long id, HttpServletResponse res
... 

并返回以下内容:

return new ResponseEntity(HttpStatus.NOT_FOUND);

【讨论】:

准确地说,您应该返回 ResponseEntity,其中 T 是例如 Response(有问题的第一种情况)。当它是正确的响应时,您将返回 new ResponseEntity(myResponse, HttpStatus.OK)。 这种方式也可以设置标题,ResponseStatus 不行,哇! 另一个好处是它不会导致日志中出现警告,而抛出 ResponseStatusException 会。 但是您会丢失响应上的类型,这与 Swagger 生成的文档无法正常工作。【参考方案4】:

你可以像这样在 res 上设置 responseStatus:

@RequestMapping(value = VIDEO_DATA_PATH, method = RequestMethod.GET)
public ResponseEntity getData(@PathVariable(ID_PARAMETER) long id,
                                            HttpServletResponse res) 
...
    res.setStatus(HttpServletResponse.SC_NOT_FOUND); 
    // or res.setStatus(404)
    return null; // or build some response entity
 ...

【讨论】:

以上是关于如何在 Spring Boot @ResponseBody 中返回 404 响应状态 - 方法返回类型是响应?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot gzip 压缩响应的大小小于配置的 min-response-size

Spring Boot rest apis 和 Response statuses 常用实践

上手spring boot项目之springboot如何返回json数据

spring boot Could not connect to SMTP host: smtp.xxx.com, port: 465, response: -1

Spring Boot实战之Filter实现简单的Http Basic认证

Spring Boot - 缓慢的请求/响应