RestTemplate 配置通过HttpClientBuilder.create()方法初始化配置信息其中Cookie是默认打开的可以通过disableCookieManagement()方法禁用Cookie回话保持功能
/**
* Rest client filter
* @return
*/
@Bean(name = "restClient")
public RestTemplate getRestClient() {
CloseableHttpClient build = HttpClientBuilder.create().disableCookieManagement().useSystemProperties().build();
RestTemplate restClient = new RestTemplate(new HttpComponentsClientHttpRequestFactory(build));
// set message converters
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
// set string converter
messageConverters.add(new StringHttpMessageConverter());
// set json converter
messageConverters.add(new MappingJackson2HttpMessageConverter());
// set form converter
messageConverters.add(new FormHttpMessageConverter());
restClient.setMessageConverters(messageConverters);
// return object
return restClient;
}
HttpClientBuilder部分源码
public CloseableHttpClient build() {
b.addAll(
new RequestDefaultHeaders(defaultHeaders),
new RequestContent(),
new RequestTargetHost(),
new RequestClientConnControl(),
new RequestUserAgent(userAgentCopy),
new RequestExpectContinue());
// 禁用Cookie后,RequestAddCookie拦截器将不再处理请求信息
if (!cookieManagementDisabled) {
b.add(new RequestAddCookies());
}
// 禁用Cookie后,ResponseProcessCookies拦截器将不再处理响应信息
if (!cookieManagementDisabled) {
b.add(new ResponseProcessCookies());
}
}
ResponseProcessCookies源码主要处理Http响应后的Cookie信息,将响应请求头信息中的Set-Cookie,Set-Cookie2保存在CookieStore中。
注:Set-Cookie2此功能已过时。虽然它可能在某些浏览器中仍然有效,但它的使用是不鼓励的,因为它可以在任何时候被删除。尽量避免使用它。过时的Set-Cookie2HTTP 响应标头用于从服务器向用户代理发送 cookie,但已被规范所弃用。Set-Cookie改为使用。
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class ResponseProcessCookies implements HttpResponseInterceptor {
private final Log log = LogFactory.getLog(getClass());
public ResponseProcessCookies() {
super();
}
@Override
public void process(final HttpResponse response, final HttpContext context)
throws HttpException, IOException {
Args.notNull(response, "HTTP request");
Args.notNull(context, "HTTP context");
final HttpClientContext clientContext = HttpClientContext.adapt(context);
// Obtain actual CookieSpec instance
final CookieSpec cookieSpec = clientContext.getCookieSpec();
if (cookieSpec == null) {
this.log.debug("Cookie spec not specified in HTTP context");
return;
}
// 获取已经存储的Cookie信息
final CookieStore cookieStore = clientContext.getCookieStore();
if (cookieStore == null) {
this.log.debug("Cookie store not specified in HTTP context");
return;
}
// 获取Http请求后响应的Cookie信息
final CookieOrigin cookieOrigin = clientContext.getCookieOrigin();
if (cookieOrigin == null) {
this.log.debug("Cookie origin not specified in HTTP context");
return;
}
// 读取响应的Set-Cookie请求头信息
HeaderIterator it = response.headerIterator(SM.SET_COOKIE);
// 将Set-Cookie写入本地
processCookies(it, cookieSpec, cookieOrigin, cookieStore);
// 查看cookie规范是否支持cookie版本控制。
if (cookieSpec.getVersion() > 0) {
// 读取响应的Set-Cookie2 请求头信息
it = response.headerIterator(SM.SET_COOKIE2);
// 将Set-Cookie2写入本地
processCookies(it, cookieSpec, cookieOrigin, cookieStore);
}
}
private void processCookies(
final HeaderIterator iterator,
final CookieSpec cookieSpec,
final CookieOrigin cookieOrigin,
final CookieStore cookieStore) {
while (iterator.hasNext()) {
final Header header = iterator.nextHeader();
try {
final List<Cookie> cookies = cookieSpec.parse(header, cookieOrigin);
for (final Cookie cookie : cookies) {
try {
// 检查Host Domain 过期时间等数据,如果数据不符合会抛出MalformedCookieException
cookieSpec.validate(cookie, cookieOrigin);
// 写入CookieStore中保持
cookieStore.addCookie(cookie);
if (this.log.isDebugEnabled()) {
this.log.debug("Cookie accepted [" + formatCooke(cookie) + "]");
}
} catch (final MalformedCookieException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn("Cookie rejected [" + formatCooke(cookie) + "] "
+ ex.getMessage());
}
}
}
} catch (final MalformedCookieException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn("Invalid cookie header: \""
+ header + "\". " + ex.getMessage());
}
}
}
}
}
RequestAddCookies 源码 1.查找当前Domain下的Cookie信息存储在matchedCookies中 2.检查是否Cookie超时 3.匹配Domain信息,将符合该Domain的Cookie取出存储在matchedCookies中 4.如果有过期Cookie需要清理(超过当前时间的Cookie都清理掉)。5.Header添加Cookie信息(Cookie,Cookie2)
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class RequestAddCookies implements HttpRequestInterceptor {
private final Log log = LogFactory.getLog(getClass());
public RequestAddCookies() {
super();
}
@Override
public void process(final HttpRequest request, final HttpContext context)
throws HttpException, IOException {
Args.notNull(request, "HTTP request");
Args.notNull(context, "HTTP context");
final String method = request.getRequestLine().getMethod();
// 忽略http connect方法
if (method.equalsIgnoreCase("CONNECT")) {
return;
}
final HttpClientContext clientContext = HttpClientContext.adapt(context);
// 读取CookieStore中的Cookie信息(在ResponseProcessCookies写入的)
final CookieStore cookieStore = clientContext.getCookieStore();
if (cookieStore == null) {
this.log.debug("Cookie store not specified in HTTP context");
return;
}
// Obtain the registry of cookie specs
final Lookup<CookieSpecProvider> registry = clientContext.getCookieSpecRegistry();
if (registry == null) {
this.log.debug("CookieSpec registry not specified in HTTP context");
return;
}
// Obtain the target host, possibly virtual (required)
final HttpHost targetHost = clientContext.getTargetHost();
if (targetHost == null) {
this.log.debug("Target host not set in the context");
return;
}
// Obtain the route (required)
final RouteInfo route = clientContext.getHttpRoute();
if (route == null) {
this.log.debug("Connection route not set in the context");
return;
}
final RequestConfig config = clientContext.getRequestConfig();
String policy = config.getCookieSpec();
if (policy == null) {
policy = CookieSpecs.DEFAULT;
}
if (this.log.isDebugEnabled()) {
this.log.debug("CookieSpec selected: " + policy);
}
URI requestURI = null;
if (request instanceof HttpUriRequest) {
requestURI = ((HttpUriRequest) request).getURI();
} else {
try {
requestURI = new URI(request.getRequestLine().getUri());
} catch (final URISyntaxException ignore) {
}
}
final String path = requestURI != null ? requestURI.getPath() : null;
final String hostName = targetHost.getHostName();
int port = targetHost.getPort();
if (port < 0) {
port = route.getTargetHost().getPort();
}
final CookieOrigin cookieOrigin = new CookieOrigin(
hostName,
port >= 0 ? port : 0,
!TextUtils.isEmpty(path) ? path : "/",
route.isSecure());
// Get an instance of the selected cookie policy
final CookieSpecProvider provider = registry.lookup(policy);
if (provider == null) {
if (this.log.isDebugEnabled()) {
this.log.debug("Unsupported cookie policy: " + policy);
}
return;
}
final CookieSpec cookieSpec = provider.create(clientContext);
// Get all cookies available in the HTTP state
final List<Cookie> cookies = cookieStore.getCookies();
// 查找当前Domain下的Cookie信息存储在matchedCookies中
final List<Cookie> matchedCookies = new ArrayList<Cookie>();
final Date now = new Date();
boolean expired = false;
for (final Cookie cookie : cookies) {
// 检查是否Cookie超时
if (!cookie.isExpired(now)) {
//匹配Domain信息,将符合该Domain的Cookie取出存储在matchedCookies中。
if (cookieSpec.match(cookie, cookieOrigin)) {
if (this.log.isDebugEnabled()) {
this.log.debug("Cookie " + cookie + " match " + cookieOrigin);
}
// 存储在matchedCookies
matchedCookies.add(cookie);
}
} else {
if (this.log.isDebugEnabled()) {
this.log.debug("Cookie " + cookie + " expired");
}
//标记Cookie过期
expired = true;
}
}
// 如果有过期Cookie需要清理(超过当前时间的Cookie都清理掉)。
if (expired) {
cookieStore.clearExpired(now);
}
// 如果匹配到Cookie数据
if (!matchedCookies.isEmpty()) {
final List<Header> headers = cookieSpec.formatCookies(matchedCookies);
// 将Cookie加入Http请求头中
for (final Header header : headers) {
// 实际上Header中存储的信息为:(Cookie:TOKEN=8CB982A185805907846DB042C469104;JSESSIONID=282294701B045845915AF1466B84527D)
request.addHeader(header);
}
}
final int ver = cookieSpec.getVersion();
if (ver > 0) {
// 获取Cookie2的请求信息(Cookie2:TOKEN=8CB982A185805907846DB042C469104;JSESSIONID=282294701B045845915AF1466B84527D)
final Header header = cookieSpec.getVersionHeader();
if (header != null) {
// 将Cookie2加入Http请求头中
request.addHeader(header);
}
}
// Stick the CookieSpec and CookieOrigin instances to the HTTP context
// so they could be obtained by the response interceptor
context.setAttribute(HttpClientContext.COOKIE_SPEC, cookieSpec);
context.setAttribute(HttpClientContext.COOKIE_ORIGIN, cookieOrigin);
}
}
网友评论