架构

HTTP 会话处理

师成师成· 更新于 2026-09-28· 阅读 13 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

HTTP 会话处理

多个 Camel 组件可以使用 HTTP 作为底层传输协议。

通常情况下,HTTP 调用本质上是无状态的,但某些服务器允许通过 Cookie 来维持状态。Cookie 常用于维护服务器会话(例如,在实现 JEE Servlet 规范的服务器上,使用名为 "JSESSIONID" 的会话 Cookie)。

会话作用域

如果 Camel 路由打算实现某种 HTTP 会话处理,就需要考虑该会话的作用域。

无论会话作用域如何,实现都必须遵守所处理 Cookie 的域。

路由/上下文作用域

可能希望为某个路由或 CamelContext 使用单个会话。这本质上意味着,从该路由或 CamelContext 发出的对服务器的所有调用共享同一个 HTTP 会话。

端点作用域

也可以在 Endpoint 实体上建立会话。这意味着由单个 Endpoint 发出的所有 HTTP 调用共享一个会话,而不同的 Endpoint 永远不会共享会话,即使调用是发送到同一台服务器。

Exchange 作用域

定义会话作用域的第三种方式是在 Exchange 级别上。这在服务器会话确实需要维护状态的场景中特别有用。

在这种情况下,路由可以先执行登录调用,然后执行若干更新调用,最后执行注销调用。如果将会话处理定义在路由或 CamelContext 作用域上,看似可以正常运行,但在负载较高时,对该路由的并行调用会共享同一个会话,从而可能导致问题。如果将会话定义在 Exchange 作用域上,则每次路由调用都会获得单独的会话,服务器可以为不同的并行调用分别维护状态。

用法

作为 Camel 用户,你会看到多个 Camel 组件在端点级别上支持 cookieHandler 参数。你只需实例化一个适合自身用例的 Cookie 处理器,并在所有需要参与 HTTP 会话的端点中引用该 cookieHandler 参数即可。

已预先实现了两个 Cookie 处理器:

  • org.apache.camel.http.common.cookie.InstanceCookieHandler
  • org.apache.camel.http.common.cookie.ExchangeCookieHandler

InstanceCookieHandler 将 cookie 存储在其自身实例中。可以将其类比为一个在所有使用它的端点之间共享的浏览器实例(并且这些端点的所有调用都会使用它)。如果希望为不同端点或端点组维护相互独立的会话,可以创建多个 InstanceCookieHandler 实例。

ExchangeCookieHandler 将会话存储在 Exchange 中。用浏览器来类比,这意味着每个 Exchange 都会拥有自己的浏览器实例(因此会话彼此隔离)。由于 ExchangeCookieHandler 不保存任何状态,通常没有必要创建多个 ExchangeCookieHandler 实例(因为无论如何它们访问的都是同一份数据)。

示例

以下三条路由各自会对一个回显 REST 服务调用两次。在第一条路由(未使用 cookie 处理器)中,每次调用都会获得新的会话。对于第二条路由,所有调用共享同一个会话。对于第三条路由,该路由内的第一次调用和第二次调用共享同一个会话,但对该路由的不同调用(即使是并行调用)之间不会共享会话。

  • Spring XML
  • YAML
  <cxf:rsClient id="rsClientProxy" address="http://127.0.0.1:8080/CxfRsProducerSessionTest/"
    serviceClass="org.apache.camel.component.cxf.jaxrs.testbean.EchoService"
    loggingFeatureEnabled="true" />

  <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
    <route>
       <from uri="direct://proxy"/>
       <to uri="cxfrs://bean://rsClientProxy"/>
       <convertBodyTo type="java.lang.String"/>
       <to uri="cxfrs://bean://rsClientProxy"/>
    </route>
    <route>
       <from uri="direct://proxyinstance"/>
       <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#instanceCookieHandler"/>
       <convertBodyTo type="java.lang.String"/>
       <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#instanceCookieHandler"/>
    </route>
    <route>
       <from uri="direct://proxyexchange"/>
       <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#exchangeCookieHandler"/>
       <convertBodyTo type="java.lang.String"/>
       <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#exchangeCookieHandler"/>
    </route>
  </camelContext>

  <bean id="instanceCookieHandler" class="org.apache.camel.http.common.cookie.InstanceCookieHandler"/>
  <bean id="exchangeCookieHandler" class="org.apache.camel.http.common.cookie.ExchangeCookieHandler"/>
- route:
    from:
      uri: direct://proxy
      steps:
        - to:
            uri: cxfrs://bean://rsClientProxy
        - convertBodyTo:
            type: java.lang.String
        - to:
            uri: cxfrs://bean://rsClientProxy
- route:
    from:
      uri: direct://proxyinstance
      steps:
        - to:
            uri: cxfrs://bean://rsClientProxy
            parameters:
              cookieHandler: "#instanceCookieHandler"
        - convertBodyTo:
            type: java.lang.String
        - to:
            uri: cxfrs://bean://rsClientProxy
            parameters:
              cookieHandler: "#instanceCookieHandler"
- route:
    from:
      uri: direct://proxyexchange
      steps:
        - to:
            uri: cxfrs://bean://rsClientProxy
            parameters:
              cookieHandler: "#exchangeCookieHandler"
        - convertBodyTo:
            type: java.lang.String
        - to:
            uri: cxfrs://bean://rsClientProxy
            parameters:
              cookieHandler: "#exchangeCookieHandler"

两种 CookieHandler 实现都支持设置 CookiePolicy,以控制存储 Cookie 的策略。默认值为 CookiePolicy.ACCEPT_ORIGINAL_SERVER。

Cookie 与 EIP

某些 EIP(如 Multicast 或 Split)会从单个 Exchange 创建多个 Exchange。如果在此之前没有使用 org.apache.camel.http.common.cookie.ExchangeCookieHandler,那么每个 multicast 或 splitter 分支都将拥有各自的 cookie 存储。如果使用了 cookie 处理器的某个端点的首次调用发生在 multicast 之前,则情况并非如此,因为此时 cookie 存储会附加到原始 Exchange 上,而 multicast 创建的 Exchange 会复制对该 cookie 存储的引用,从而在各分支之间实现共享的 cookie 存储。作为变通办法,你可以调用 cookieHandler.getCookieStore(),例如将其设置到某个占位头部中。

组件开发者

如果你希望开发一个参与会话的基于 HTTP 的组件,则需要在代码中添加以下部分:

  1. 包含对 camel-http-base 的构建引用(如果尚不存在)
  2. 为端点类添加 cookieHandler 参数(以及相应的 getter 和 setter)
  3. 在你的代码执行 HTTP 调用之前,如果端点上设置了 cookie 处理器,则执行 cookieHandler.loadCookies(exchange, uri) 调用。它将返回一个 Map<String, List<String>>,其中包含需要发送给服务器的请求头。如何将这些请求头发送给服务器的具体细节,取决于你所使用的底层 HTTP API。
  4. 在你的代码接收到 HTTP 响应之后,如果端点上设置了 cookie 处理器,则执行 cookieHandler.storeCookies(exchange, uri, m) 调用。m 是一个 Map<String, List<String>>,其中包含服务器返回的 HTTP 头。
某些 API 对 Cookie 处理提供了更直接的支持。在这种情况下,通过 cookeManager.getCookieStore(exchange) 调用获取底层的 java.net.CookieStore,并使用底层库提供的 cookie 接口来处理 Cookie,可能会更加方便。

评论

登录后参与评论

正在加载评论…