【问题标题】:How to set HTTP Status code reason with Apache Camel REST DSL (Servlet/Restlet)如何使用 Apache Camel REST DSL (Servlet/Restlet) 设置 HTTP 状态代码原因
【发布时间】:2018-02-19 10:23:20
【问题描述】:

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

应该如何:

< 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")),但结果是一样的。

【问题讨论】:

  • 试试没有这部分.component("restlet")
  • @pvpkiran 结果一模一样
  • 对我来说有效。没有setBody。这是结果curl --verbose http://localhost:8080/overlay/ * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 8080 (#0) &gt; GET /overlay/ HTTP/1.1 &gt; Host: localhost:8080 &gt; User-Agent: curl/7.47.0 &gt; Accept: */* &gt; &lt; HTTP/1.1 403 Forbidden &lt; Server: Restlet-Framework/2.3.6 &lt; Breadcrumbid: ID-Boss-36986-1519039039690-0-5 &lt; Date: Mon, 19 Feb 2018 11:19:34 GMT &lt; Content-type: application/json; charset=UTF-8 &lt; Content-length: 0
  • @pvpkiran 您能否分享您的测试代码和软件包版本,以便我进行比较?谢谢。
  • 我有和你一样的代码。除了.component("restlet"),我也没有 ServletRegistrationBean、Component、RestletComponent bean 声明。我们不需要这个

标签: java rest spring-boot apache-camel restlet


【解决方案1】:
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
.setHeader(Exchange.CONTENT_TYPE, constant("text/plain"))
.setBody(constant("Forbidden"))

【讨论】:

  • 那不适合我。正文内容类型已正确设置。
【解决方案2】:

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

如果没有自定义核心,我相信你做不到:

响应正在发送到org.restlet.engine.adapter.ServerCall.sendResponse(),其中响应的头部和主体是written to the OutputStream

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

...和writeResponseHead(response) 默认情况下什么都不做check it

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

更新: ... 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);
}

更新 2: ...DefaultRestletBinding.populateRestletResponseFromExchange 执行以下操作:

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

...它只使用Status.valueOf

虽然有Status.reasonPhrase,但无法访问。


答案:

没有自定义核心,(我相信)你做不到!


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

6.1.1 状态码和原因短语

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

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

3.1.2.状态行

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

8.1.2.4。响应伪标头字段

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

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

请参阅complete list of status codes maintained by IANA

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多