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