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

clj7thdc  于 2022-11-07  发布在  Apache
关注(0)|答案(3)|浏览(145)

我有一个使用Sping 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

它应该是:

< 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

如何配置Camel/Restlet/Servlet以在HTTP状态代码中包含原因?
我的当前配置:
Application.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());
    }

}

路由配置:

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

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

pw9qyyiw

pw9qyyiw1#

.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
.setHeader(Exchange.CONTENT_TYPE, constant("text/plain"))
.setBody(constant("Forbidden"))
ws51t4hk

ws51t4hk2#

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

如果没有自定义内核,我相信您将无法:

响应是在org.restlet.engine.adapter.ServerCall.sendResponse()中发送的,其中响应头和主体被写入OutputStream:

writeResponseHead(response); // <--
if (responseEntity != null) {
    responseEntityStream = getResponseEntityStream();
    writeResponseBody(responseEntity, responseEntityStream);
}

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

protected void writeResponseHead(Response response) throws IOException {
    // Do nothing by default
}

更新:... HttpStatus(value,reasonPhrase)具有reasonPhrase,但不用于字符串化:

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

更新2:...来自Exchange的DefaultRestletBinding.populateRestletResponseFromExchange执行以下操作:

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

...它只使用Status.值。
虽然有一个Status.reasonPhrase,但它是不可访问的。

答案:

没有自定义内核,(I believe)您无法实现!

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

  • RFC 2616 -超文本传输协议- HTTP/1.1:
    6.1.1状态代码和原因说明

(...)客户端不需要检查或显示Reason-Phrase。
(...)原因短语(......)可替换为本地等效短语,而不会影响方案。

  • RFC 7230 -超文本传输协议(HTTP/1.1):消息语法和路由:
    3.1.2.状态行

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

  • RFC 7540 -超文本传输协议第2版(HTTP/2):
    8.1.2.4.响应伪标头字段

(...)HTTP/2没有定义一种方式来携带版本或原因短语,而版本或原因短语包含在HTTP/1.1状态行中。

需要了解状态代码的含义?

请参阅complete list of status codes maintained by IANA

kg7wmglp

kg7wmglp3#

TLDR-使用.setHeader(Exchange.HTTP_RESPONSE_CODE, 403)

我发现
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))不工作,但
.setHeader(Exchange.HTTP_RESPONSE_CODE, 403)确实如此。
请注意constant关键字的区别。直接在路由中设置值时,您需要使用constant,但在处理器中则不需要。因此,只要代码中发生异常,您就可以设置响应状态代码,而不是在路由生成器配置中。

相关问题