处理http请求时出现Apache Camel异常

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

当我收到一个http 401错误时,我使用onException来捕获HttpOperationFailedException(尽管我还没有找到具体的捕获401的方法)。当我看到其中一个错误时,我想确保令牌是新的,所以我重新生成一个令牌并设置头部。
这里是一个简化的例子,去掉我知道的工作,并使用一些硬编码。

onException(HttpOperationFailedException.class).maximumRedeliveries(1)
    .setHeader("Authorization", constant("abcde"))
    .log("Newly Set Header: ${headers.Authorization} ${body}");

from("jms:queue:Queue")
    .unmarshal(receiptFormat)
    .bean(ModelTranslator.class, "reqest")
    .marshal(requestFormat)
    .setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
    .setHeader("Accept", constant("application/json"))
    .setHeader(Exchange.HTTP_METHOD, constant(org.apache.camel.component.http.HttpMethods.POST))
    .setHeader("Authorization", constant("12345"))
    .to("log:DEBUG?showBody=true&showHeaders=true")
    .to("https://test.net/rest/api/email")
    .to("log:DEBUG?showBody=true&showHeaders=true");

我故意在请求https://test.net/rest/api/email之前设置了一个错误的标记,这导致了错误。我成功地捕获了它,并设置了正确的标记。我可以看到正确的标记是用.log()设置的。如果我理解正确,onException将从失败的地方开始重试,也就是.to(“https://test.net/rest/api/email“),对吗?
但是调用https://test.net/rest/api/email失败,仍然出现401 ...所以我做错了什么。

kt06eoxx

kt06eoxx1#

onException.maximumRedeliveries(1)之后的逻辑只有在重新交付失败时才会被调用。This means that the .setHeader("Authorization", constant("abcde"))在重新交付已经完成后执行,并且由于.handled(true)没有被调用,路由的执行将停止到异常。
如果您想更改令牌并使用新令牌再次调用http producer-endpoint,则可以使用try-catch来完成此操作。

from("jms:queue:Queue")
    //...
    .setHeader("Authorization", constant("12345"))
    .to("log:DEBUG?showBody=true&showHeaders=true")
    .doTry()
        .to("https://test.net/rest/api/email")
    .doCatch(HttpOperationFailedException.class)
         .setHeader("Authorization", constant("abcde"))
         .log("Newly Set Header: ${headers.Authorization} ${body}")
         .to("https://test.net/rest/api/email")
    .end()
    .to("log:DEBUG?showBody=true&showHeaders=true");

或者,您也可以对onException执行相同的操作,但我宁愿避免定义全局异常处理程序,而使用路由特定的异常处理程序。

from("jms:queue:Queue")
    .onException(HttpOperationFailedException.class)
        .setHeader("Authorization", constant("abcde"))
        .log("Newly Set Header: ${headers.Authorization} ${body}")
        .to("https://test.net/rest/api/email")
        // Use handled(true) if you want to stop the route instead.
        .continued(true)
    .end()
    // ...
    .setHeader("Authorization", constant("12345"))
    .to("log:DEBUG?showBody=true&showHeaders=true")
    .to("https://test.net/rest/api/email")
    .to("log:DEBUG?showBody=true&showHeaders=true");
qltillow

qltillow2#

Pasi发布的另一种方法是在您调用的端点上指定throwExceptionOnFailure设置为false,以防止Camel在您自己处理该事件时引发异常。
在下一步中,您只需定义一个choice,它查询当前处理的exchange的头中存在的HTTP响应代码,并在需要处理的情况下触发所需的业务逻辑:

route("direct:perform_request")
  .routeId("performRequest")
  .to("http4:....?throwExceptionOnFailure=false")
  .choice()
    .when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo(401))
      // divert to a different route responsible for creating the token which 
      // is stored in the exchange headers
      .to("direct:generate_auth_token");
      // ... use the generated token of the previous route which should be available 
      // in the headers to update the authorization header
      .setHeader("Authorization", header(HeaderConstants.AUTH_TOKEN)
      // invoke itself with the updated credentials
      .to("direct:perform_request")
      ...
    .endChoice()
    .when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo(400))
      // handle bad request responses here
      ...
    .endChoice()
    .otherwise()
      // regular stuff, if needed
      ...
    .endChoicee()
  .end()
  ...

然而,这种方法在当前情况下可能不是最佳的,因为您需要或多或少地将该逻辑重构为您自己的路由,只要响应不满足您的期望,您就将交换传递到该路由。您可能还需要保留原始消息,因为生成令牌的路由以及请求的初始响应可能会更新已处理交换的当前消息体。
这里的异常处理器的优点在于,一旦异常得到解决,Camel将从最初发生的异常点继续执行,如果可以解决的话。最重要的是,.useOriginalBody()保证使用最初使用的消息有效负载。
这里概述的示例只是说明了Camel中有多种方法来实现这些功能。虽然这种方法可能更灵活,但它也给您带来了更多的负担,因为您需要更仔细地设计通过路由的交换流,并在某些头或消息正文本身被修改时进行评估。

相关问题