如何在HTTP状态代码后添加自定义消息

时间:2018-08-09 08:41:51

标签: spring spring-mvc spring-boot

我将Spring Boot用作Web服务器,有时想响应[HTTP / 1.1 403 XXX]。

我尝试将ResponseEntity@ResponseStatusresponse.sendError(403, "XXX")一起使用,但我嗅探到数据包发现Web服务器仅响应[HTTP / 1.1 403]

CURL示例:

[root@localhost ~]# curl -v 192.168.12.36:8080/test
* About to connect() to 192.168.12.36 port 8080 (#0) 
*   Trying 192.168.12.36...
* Connected to 192.168.12.36 (192.168.12.36) port 8080 (#0)
> GET /test HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.12.36:8080
> Accept: */*
> 
< HTTP/1.1 403 
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 09 Aug 2018 08:26:37 GMT
< 
* Connection #0 to host 192.168.12.36 left intact

我需要的答复是:

< HTTP/1.1 403 XXX
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
...

如何在HTTP状态代码后添加自定义消息?

3 个答案:

答案 0 :(得分:2)

您可能希望HTTP响应的主体包含一条消息,您可以将其与任何其他信息一起解析。

状态码(在响应中)上的HTTP状态消息可以是您想要的任何内容,并且不会影响任何客户端。 HTTP客户端通常会忽略消息文本。

这是另一种选择。创建一个接受状态码和消息的通用异常。然后创建一个异常处理程序。使用异常处理程序从异常中检索信息,然后返回到服务的调用者。

http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/

public class ResourceException extends RuntimeException {

    private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public ResourceException(HttpStatus httpStatus, String message) {
        super(message);
        this.httpStatus = httpStatus;
    }
}

然后使用异常处理程序检索信息并将其返回给服务调用者。

@ControllerAdvice
public class ExceptionHandlerAdvice { 

    @ExceptionHandler(ResourceException.class)
    public ResponseEntity handleException(ResourceException e) {
        // log exception 
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }         
} 

然后在需要时创建一个例外。

throw new ResourceException(HttpStatus.NOT_FOUND, "We were unable to find the specified resource.");

答案 1 :(得分:1)

您在问题中没有这么说,但我想您正在使用Tomcat。默认情况下,Tomcat仅发送状态代码,不发送原因短语。原因短语是HTTP规范的可选部分,因此我不建议依赖它来发送。

如果您真的要依赖自定义原因短语,而不是像其他答案所建议的那样使用响应正文,则必须配置Tomcat发送原因短语(仅Tomcat 8.5支持)切换到另一个容器。对于Spring Boot支持的嵌入式servlet容器,Jetty和Undertow都将发送原因短语。

下面是一个小示例,该示例将Tomcat配置为既发送原因短语又启用自定义短语:

package sample.tomcat;

import javax.servlet.http.HttpServletResponse;

import org.apache.coyote.AbstractProtocol;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@SpringBootApplication
public class SampleTomcatApplication {

    @Bean
    public EmbeddedServletContainerCustomizer tomcatCustomizer() {
        return (container) -> {
            if (container instanceof TomcatEmbeddedServletContainerFactory) {
                ((TomcatEmbeddedServletContainerFactory) container)
                        .addConnectorCustomizers((connector) -> {
                            ((AbstractProtocol<?>) connector.getProtocolHandler())
                                    .setSendReasonPhrase(true);
                        });
            }
        };
    }

    public static void main(String[] args) throws Exception {
        System.setProperty("org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER", "true");
        SpringApplication.run(SampleTomcatApplication.class, args);
    }

}

@Controller
class SampleController {

    @GetMapping("/")
    public void customReasonPhrase(HttpServletResponse response) throws Exception {
        response.setStatus(503, "Custom");
    }

}

答案 2 :(得分:0)

您可以在@ResponseStatus注释中设置原因:

@ResponseStatus(value = HttpStatus.FORBIDDEN, reason="You custom reason")