【问题标题】:Apache Camel REST DSL - Validating Request Payload and return error responseApache Camel REST DSL - 验证请求有效负载并返回错误响应
【发布时间】:2018-08-07 05:36:06
【问题描述】:

我正在使用“CamelHttpTransportServlet”公开一个休息服务,该服务接收订单并放置在 jms 队列中。该代码在快乐路径上运行良好并返回 200 响应。 我编写了处理器来验证输入 JSON,并根据输入设置 http_response_code。

问题是 - 对于通过失败响应代码的无效请求 - 设置了 400,流程继续到下一个路由并将数据推送到队列,而不是将 400 响应发送回调用应用程序。

    rest("/ordermanagement")
     .post("/order").to("direct:checkInput");

   from("direct:checkInput")         
     .process(new Processor() { 
         @Override 
         public void process(final Exchange exchange) throws Exception { 

             String requestBody = exchange.getIn().getBody(String.class); 
                 if(requestBody == "" || requestBody== null) {                      
                     exchange.getIn().setBody("{ "error": Bad Request}");
                     exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
                     exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
                 }
         } 
 })
.to("direct:sendToQ");

from("direct:sendToQ")
    .to("jms:queue:orderReceiver")
    .log("Sent to JMS");

有人可以告知这里缺少的内容并在可能的情况下提供示例吗?

尝试实现 onException 方法:

   rest("/ordermanagement")
 .post("/order").to("direct:checkInput");


   onException(CustomException.class).handled(true)
 .setHeader(Exchange.HTTP_RESPONSE_CODE, code)
 .setBody(jsonObject);

  from("direct:checkInput")         
 .process(new Processor() { 
     @Override 
     public void process(final Exchange exchange) throws Exception { 

         String requestBody = exchange.getIn().getBody(String.class); 
             if(requestBody == "" || requestBody== null) {                      
                 throw CustomException(code, jsonObject)
             }
     } 
  })
  .to("direct:sendToQ");

  from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");

但是我不知道如何将参数 - code,jsonObject 从处理器传递到 onException 块。

对此有任何帮助吗?这可行吗?

【问题讨论】:

  • 您是否尝试将.to("direct:checkInput") 替换为.inOut("direct:checkInput").to(ExchangePattern.InOut, "direct:checkInput")?我进一步不确定您是否想将错误有效负载真正发送到 JMS 队列,您可以通过将消息正文替换为自定义错误正文来执行此操作。可能抛出一个验证错误并在自己的异常处理程序中处理它是更好的选择,因为队列可能应该只填充有效的订单
  • 我需要将错误消息发送给消费者,而不是发送给队列。

标签: rest error-handling apache-camel dsl


【解决方案1】:

我会使用下面代码示例中的内容:

onException(CustomException.class)
    .handled(true)
    .bean(PrepareErrorResponse.class)
    .log("Error response processed");

rest("/ordermanagement")
    .post("/order")
        .to("direct:checkInput");

from("direct:checkInput")     
    .process((Exchange exchange) -> { 
         String requestBody = exchange.getIn().getBody(String.class); 
         if(requestBody == "" || requestBody== null) {                      
             throw new CustomException(code, jsonObject);
         }
    })
    .to("direct:sendToQ");

from("direct:sendToQ")
    .to("jms:queue:orderReceiver")
    .log("Sent to JMS");

Camel 将存储在交换的属性中捕获的任何异常,因此应该可以通过 Exchange.EXCEPTION_CAUGHT 属性键获得。下面的示例说明了这种自定义错误消息 bean 的外观:

public class PrepareErrorResponse {

    @Handler
    public void prepareErrorResponse(Exchange exchange) {
        Throwable cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);

        if (cause instanceof CustomException) {
            CustomException validationEx = (CustomException) cause;
            // ...
        }

        Message msg = exchange.getOut();
        msg.setHeader(Exchange.CONTENT_TYPE, MediaType.APPLICATION_JSON);
        msg.setHeader(Exchange.HTTP_RESPONSE_CODE, 400);

        JsonObject errorMessage = new JsonObject();
        errorMessage.put("error", "Bad Request");
        errorMessage.put("reason", cause.getMessage());
        msg.setBody(errorMessage.toString());
        // we need to do the fault=false below in order to prevent a 
        // HTTP 500 error code from being returned
        msg.setFault(false);
    }
}

Camel 提供了几种实际处理异常的方法。这里介绍的方式只是一个例子。然而,提议的代码允许对不同的捕获异常以及其他内容使用自定义重新传递策略。如果错误可以在异常处理程序中得到解决,则在发生异常的点继续路由(即应用了重新传递策略的临时网络问题)。如果错误无法在处理程序中得到修复,则交换将停止。然后通常会将当前处理的消息发送到 DLQ 并记录有关错误的信息。

请注意,此示例将假定 CustomExceptionunchecked exception,因为处理器被替换为更简单的 lambda。如果您不能或不想使用此类异常(或 lambda 表达式),请将 lambda-processor 替换为 new Processor() { @Override public void process(Exchange exchange) throws Exception { ... } } 构造。

【讨论】:

    【解决方案2】:

    这是一种方法。你可以使用choice

        rest("/ordermanagement")
            .post("/order").to("direct:checkInput");
    
        from("direct:checkInput")
            .process(exchange -> {
              String requestBody = exchange.getIn().getBody(String.class);
              if(requestBody == null || requestBody.equals("")) {
                exchange.getIn().setBody("{ "error": Bad Request}");
                exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
                exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
              }
            })
            .choice()
            .when(exchange -> {
              Object header = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE);
              return header != null && header.equals(400);
            })
            .stop()
            .otherwise()
            .to("direct:sendToQ")
            .endChoice();
    
        from("direct:sendToQ")
            .to("jms:queue:orderReceiver")
            .log("Sent to JMS");
    

    【讨论】:

    • 感谢这个工作,但是我试图实现 onException 来处理错误。用这种方法再次更新了问题,如果可能,您能否检查并提出建议?
    • 为什么要抛出异常?你从中获得了什么?
    • 什么是jsonObject和你代码中的代码throw CustomException(code, jsonObject)
    • 这是我的首选方法。不要将异常用于控制流或验证。因此,您的代码会更简洁。
    【解决方案3】:

    在处理器中将 ROUTE_STOP 属性设置为 true 应该可以防止进一步流动并返回您的响应:

    ...
    exchange.getIn().setBody("{ "error": Bad Request}");
    exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
    exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
    
    exchange.setProperty(Exchange.ROUTE_STOP, Boolean.TRUE);
    ...
    

    【讨论】:

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