美文网首页
Springboot RestTemplate Cookie回话

Springboot RestTemplate Cookie回话

作者: xuchengsheng | 来源:发表于2019-08-19 14:47 被阅读0次

    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);
        }
    
    }
    

    相关文章

      网友评论

          本文标题:Springboot RestTemplate Cookie回话

          本文链接:https://www.haomeiwen.com/subject/lapnrctx.html