ChatGPT解决这个技术问题 Extra ChatGPT

How to return 404 response status in Spring Boot @ResponseBody - method return type is Response?

I'm using Spring Boot with @ResponseBody based approach like the following:

@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());
}

I tried some typical approaches as:

res.setStatus(HttpStatus.NOT_FOUND.value()); new ResponseEntity(HttpStatus.BAD_REQUEST);

but I need to return Response.

How to return here 404 status code if video is null?


d
dur

This is very simply done by throwing org.springframework.web.server.ResponseStatusException:

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

It's compatible with @ResponseBody and with any return value. Requires Spring 5+


Is there some way of doing this without causing Springboot to issue a warning? I get ` WARN 27604 --- [nio-8081-exec-9] .w.s.m.a.ResponseStatusExceptionResolver : Resolved [org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND ` which finds its way into alerts etc unreasonably: this is not a problem.
@GreenAsJade I am not sure where is this warning logged (I have not seen this warning in my logs) but maybe you can play with log4j settings or talk to your alert system to avoid this.
This is not the best, your visitors will see the error stack information.
@BuffK this is for web services (talking to machines)
This requires overring the /error endpoint.
c
chrylis -cautiouslyoptimistic-

Create a NotFoundException class with an @ResponseStatus(HttpStatus.NOT_FOUND) annotation and throw it from your controller.

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

Need the standard imports means:import org.springframework.http.HttpStatus;
@andrej That's a good solution some of the time, but (1) ResponseStatusException was not added until Spring 5; (2) A NotFoundException can be useful for either being caught or for a dual-stack HTML UI with an @ExceptionHandler.
This solution tightly couples the Exception to your REST-Controller layer. Something I would want to avoid. I'd use an @ExceptionHandler in an @AroundAdvice component instead
If someone wants to use a preexisting exception that comes with Spring, org.springframework.data.rest.webmvc.ResourceNotFoundException already is annotated with @ResponseStatus(HttpStatus.NOT_FOUND)
d
dur

Your original method can return ResponseEntity (doesn't change your method behavior):

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

and return the following:

return new ResponseEntity(HttpStatus.NOT_FOUND);

To be precise, you should return ResponseEntity, where T is for example Response (first case in question). And you'll return new ResponseEntity(myResponse, HttpStatus.OK) when it is a correct response.
This way allows you to set headers as well, ResponseStatus doesn't, woot!
Another good thing about this is it doesn't result in warnings in the log, which throwing the ResponseStatusException does.
But then you lose the type on the Response, which won't work well with Swagger generated documentation.
M
Michał

You can just set responseStatus on res like this:

@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
 ...
}