使用 spring 3 restful 以编程方式更改 http 响应状态

Posted

技术标签:

【中文标题】使用 spring 3 restful 以编程方式更改 http 响应状态【英文标题】:Programmatically change http response status using spring 3 restful 【发布时间】:2013-12-02 17:46:39 【问题描述】:

我有一个像下面这样的控制器

@Controller("myController")
@RequestMapping("api")
public class MyController 

     @RequestMapping(method = RequestMethod.GET, value = "/get/info/id", headers = "Accept=application/json")
    public @ResponseBody
    Student getInfo(@PathVariable String info) 
.................





    @ExceptionHandler(Throwable.class)
    @ResponseStatus( HttpStatus.EXPECTATION_FAILED)
    @ResponseBody
    public String handleIOException(Throwable ex) 
        ErrorResponse errorResponse = errorHandler.handelErrorResponse(ex);
        return errorResponse.toString();
    


控制器有一个错误处理机制,在错误处理选项中它总是返回期望失败状态码417。但我需要根据错误类型设置一个动态错误Http状态码,如500、403等。我该怎么做?

【问题讨论】:

【参考方案1】:

我得到了一个解决方案并打算分享这个,也想知道任何好的建议。

@Controller("myController")
@RequestMapping("api")
public class MyController 

    @RequestMapping(method = RequestMethod.GET, value = "/get/info/id", headers = "Accept=application/json")
    public @ResponseBody
    Student getInfo(@PathVariable String info) 
        // ...
    




// ...    
    @ExceptionHandler(Throwable.class)
    //@ResponseStatus( HttpStatus.EXPECTATION_FAILED)<<remove this line
    @ResponseBody
    public String handleIOException(HttpServletResponse httpRes,Throwable ex) // <<Change this 
        if (some condition) 
            httpRes.setStatus(HttpStatus.BAD_GATEWAY.value());
         else 
            httpRes.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                         
        ErrorResponse errorResponse = errorHandler.handleErrorResponse(ex);
        return errorResponse.toString();
    

预计在休息客户端:

502 Bad Gateway

    "status":"BAD_GATEWAY",
    "error":"java.lang.UnsupportedOperationException",
    "message":"Some error message"

感谢您的回复。我仍然需要一些好的做法。

【讨论】:

【参考方案2】:

按照上面的代码,您需要更加小心您正在抛出和处理哪些异常。为 Throwable 设置异常处理程序似乎过于宽泛。

我这样做的方法是使用我的 XML/JSON 编组注释创建一个 ErrorMessage 类。

@XmlRootElement(name = "error")
public class ErrorMessage 
    private Throwable exception;
    private String message;
    public ErrorMessage() 
        this.message = "";
    
    public ErrorMessage(String message) 
        this.message = message;
    
    public ErrorMessage(Throwable exception) 
        this.exception = exception;
        this.message = exception.getLocalizedMessage();
    
    @XmlTransient
    @JsonIgnore
    public Throwable getException() 
        return exception;
    
    public void setException(Throwable exception) 
        this.exception = exception;
    
    @XmlElement(name = "message")
    public String getMessage() 
        return message;
    
    public void setMessage(String message) 
        this.message = message;
    

有了这些,我倾向于创建自己的应用程序异常,然后创建我的异常处理程序方法,例如:

@ExceptionHandler(ResourceNotFoundException.class)
@ResponseBody
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorMessage handleResourceNotFoundException(ResourceNotFoundException e, HttpServletRequest req) 
    return new ErrorMessage(e);


@ExceptionHandler(InternalServerErrorException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorMessage handleInternalServerErrorException(InternalServerErrorException e, HttpServletRequest req) 
    return new ErrorMessage(e);

有了这些,我只需要从我的控制器方法中抛出适当的异常。例如,如果我抛出 ResourceNotFoundException,那么 Spring 会将其重定向到我的 handleResourceNotFoundException 方法,该方法返回 404,并且还会返回表示错误的 JSON 或 XML。

【讨论】:

我在让它与自定义异常一起工作时遇到了一些问题,所以我很高兴找到这个table about exception types that Spring maps to different status codes by default。 (与我的自定义(Spring Boot)ErrorController 配合得很好。)【参考方案3】:

您可以为您的 API 使用一个方面。如果你为你的服务定义了一个@Around 拦截器,你可以改变响应内容。

【讨论】:

【参考方案4】:

您需要更改输出值的类型ResponseEntity。在这里回答: How to respond with HTTP 400 error in a Spring MVC @ResponseBody method returning String?

【讨论】:

以上是关于使用 spring 3 restful 以编程方式更改 http 响应状态的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring Security 3.1 以编程方式登录用户

Spring Security 3 以编程方式登录

Spring REST security - 以不同的方式保护不同的 URL

如何以编程方式为 Tyrus WebSocket @ServerEndpoint 启用 WSS

以编程方式创建 WCF REST 客户端代理(在 C# 中)

以编程方式加载视图