如何使用 Apache Camel REST DSL (Servlet/Restlet) 设置 HTTP 状态码原因

Tia*_*ira 1 java rest restlet apache-camel spring-boot

我有一个使用 Spring Boot 和 Apache Camel 构建的 Web 应用程序,我正在实现一个 REST 接口。目前,使用 Camel 默认ServletRestlet组件,我没有在响应中获得 HTTP 状态代码原因。

这是我在将 HTTP 状态代码设置为 403 时得到的示例响应:

< HTTP/1.1 403 
< Date: Mon, 19 Feb 2018 10:01:21 GMT
< Server: Restlet-Framework/2.4.0
< Content-Type: application/json
< Content-Length: 75
Run Code Online (Sandbox Code Playgroud)

应该如何:

< HTTP/1.1 403 Forbidden
< Date: Mon, 19 Feb 2018 10:01:21 GMT
< Server: Restlet-Framework/2.4.0
< Content-Type: application/json
< Content-Length: 75
Run Code Online (Sandbox Code Playgroud)

如何配置 Camel/Restlet/Servlet 以在 HTTP 状态代码中包含原因?

我目前的配置:

应用程序.java

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    private static final Logger appLogger = LoggerFactory.getLogger(Application.class);
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        appLogger.info("--Application Started--");
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {

        SpringServerServlet serverServlet = new SpringServerServlet();
        ServletRegistrationBean regBean = new ServletRegistrationBean(serverServlet, "/*");

        Map<String,String> params = new HashMap<>();
        params.put("org.restlet.component", "restletComponent");

        regBean.setInitParameters(params);

        return regBean;
    }


    @Bean
    public Component restletComponent() {
        return new Component();
    }

    @Bean
    public RestletComponent restletComponentService() {
        return new RestletComponent(restletComponent());
    }

}
Run Code Online (Sandbox Code Playgroud)

路由配置:

@Component
public class RestRouteBuilder extends RouteBuilder {
    private static final Logger appLogger = LoggerFactory.getLogger(RestRouteBuilder.class);
    private Predicate isAuthorizedRequest = header(HttpHeaders.AUTHORIZATION).isNotNull();

    @Override
    public void configure() throws Exception {
        restConfiguration().component("restlet")
                           .contextPath("/overlay")
                           .bindingMode(RestBindingMode.json)
                           .skipBindingOnErrorCode(false)
                           .dataFormatProperty("prettyPrint", "true");

        rest("/")
                .get()
                .route()
                .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
                .setBody(constant("Forbidden"))
                .endRest();
    }
}
Run Code Online (Sandbox Code Playgroud)

我也尝试添加,.setHeader(Exchange.HTTP_RESPONSE_TEXT, constant("Forbidden"))但结果是一样的。

cod*_*ane 6

.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
.setHeader(Exchange.CONTENT_TYPE, constant("text/plain"))
.setBody(constant("Forbidden"))
Run Code Online (Sandbox Code Playgroud)


小智 4

如何配置 Camel/Restlet/Servlet 以在 HTTP 状态代码中包含原因?

如果没有定制核心,我相信您无法:

响应在org.restlet.engine.adapter.ServerCall.sendResponse()发送,其中响应头和正文写入 OutputStream

writeResponseHead(response); // <--
if (responseEntity != null) {
    responseEntityStream = getResponseEntityStream();
    writeResponseBody(responseEntity, responseEntityStream);
}
Run Code Online (Sandbox Code Playgroud)

...并且writeResponseHead(response) 默认情况下不执行任何操作请检查它

protected void writeResponseHead(Response response) throws IOException {
    // Do nothing by default
}
Run Code Online (Sandbox Code Playgroud)

更新: ... HttpStatus(value, ReasonPhrase)具有ReasonPhrase,但不用于stringify

HttpStatus(int value, String reasonPhrase) {
    this.value = value;
    this.reasonPhrase = reasonPhrase;
}
...
@Override
public String toString() {
    return Integer.toString(this.value);
}
Run Code Online (Sandbox Code Playgroud)

更新 2: ... DefaultRestletBindingpopulateRestletResponseFromExchange执行以下操作:

// get response code
Integer responseCode = out.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
if (responseCode != null) {
    response.setStatus(Status.valueOf(responseCode));
}
Run Code Online (Sandbox Code Playgroud)

...它只使用Status的价值

尽管有Status.reasonPhrase,但它无法访问。


回答:

无需定制核心,(我相信)你不能!


...考虑到以下情况,什么是不合适的:

6.1.1 状态代码和原因短语

(...) 客户端不需要检查或显示原因短语。

(...) 原因短语 (...) 可以用本地等效项替换,而不影响协议。

3.1.2. 状态行

(...) 客户端应该忽略原因短语内容。

8.1.2.4。响应伪标头字段

(...) HTTP/2 没有定义携带 HTTP/1.1 状态行中包含的版本或原因短语的方法。

需要知道状态代码的含义吗?

请参阅IANA 维护的状态代码的完整列表