zoukankan      html  css  js  c++  java
  • HttpClient之HttpContext使用

      Multiple request sequences that represent a logically related session should be executed with the same HttpContext instance to ensure automatic propagation of conversation context and state information between requests.

      上面这段话摘自httpclient官网,大体意思是逻辑会话相关的多个请求序列应该使用同一个HttpContext实例,这样就可以让会话信息和状态信息在多个请求之间自动广播。

      官网上还给出一段示例代码 ,我们仿着它的示例代码,重新整一个,以便于观察。

    (1) 使用springboot快迅搭建一个目标服务

    @RestController
    public class RequestController {
        @PostMapping("/request")
        public void request(HttpServletRequest request, HttpServletResponse response) {
            HttpSession session = request.getSession();
            //1. 从session中获取username
            String username = (String) session.getAttribute("username");
            String ret;
            if (username == null) {
                // 2. 从请求参数中获取username的值
                username = request.getParameter("username");
                session.setAttribute("username", username);
                ret = "login success!";
            } else {
                ret = "Having been logined " + username;
            }
            // 将ret 内容写回到response响应体中
            ServletOutputStream outputStream = null;
            PrintWriter pw = null;
    
            try {
                outputStream = response.getOutputStream();
                pw = new PrintWriter(outputStream);
                pw.write(ret);
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (pw != null) {
                    pw.close();
                }
                try {
                    if (outputStream != null) {
                        outputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    启功类省略,server.port = 9999

    (2)  HttpClient测试类

    import org.apache.http.HttpEntity;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.client.protocol.HttpClientContext;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.protocol.BasicHttpContext;
    import org.apache.http.protocol.HttpContext;
    import org.apache.http.util.EntityUtils;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class HttpContextTest {
        public static void main(String[] args) throws IOException {
            
            HttpContext httpContext = new BasicHttpContext();
            HttpClientContext httpClientContext = HttpClientContext.adapt(httpContext);
            
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost("http://localhost:9999/request");
            // 模仿form表单请求,设置请求参数
            List<NameValuePair> nvp = new ArrayList<>();
            nvp.add(new BasicNameValuePair("username", "admin"));
            // 第一次请求时,设置请求参数
            httpPost.setEntity(new UrlEncodedFormEntity(nvp));
    
            CloseableHttpResponse response = null;
            try {
                response = httpclient.execute(httpPost, httpClientContext);
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String ret = EntityUtils.toString(entity);
                    System.out.println("第一次请求响应:"+ ret);
                }
            }finally {
                response.close();
            }
    
            System.out.println("=================第二次请求====================");
            // 重新创建一个HttpPost对象,但是此次该对象中不设置请求参数
            httpPost = new HttpPost("http://localhost:9999/request");
            try {
                response = httpclient.execute(httpPost, httpClientContext);
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String ret = EntityUtils.toString(entity);
                    System.out.println("第二次请求响应:"+ ret);
                }
            }finally {
                response.close();
            }
        }
    }

    (3)启动目标项目,然后再运行测试代码,打印结果如下

      

    第一次请求响应:login success!
    =================第二次请求====================
    第二次请求响应:Having been logined admin
    
    Process finished with exit code 0

    感觉浏览器请求一模一样了, 保存了请求会话信息,事实上确实如此,此处就是保存jsessionid

    (4) 简单看下源码

    <1>  ProtocolExec#execute()

    <2> ResponseProcessCookies#process(final HttpResponse response, final HttpContext context)

      

    @Override
    public void process(final HttpResponse response, final HttpContext context)
            throws HttpException, IOException {
     
        final HttpClientContext clientContext = HttpClientContext.adapt(context);
    
        // Obtain actual CookieSpec instance
        final CookieSpec cookieSpec = clientContext.getCookieSpec();
        // Obtain cookie store
        final CookieStore cookieStore = clientContext.getCookieStore();
        
        //.......
        // see if the cookie spec supports cookie versioning.
        if (cookieSpec.getVersion() > 0) {
            // process set-cookie2 headers.
            // Cookie2 will replace equivalent Cookie instances
            // 就是将cookie信息拷到cookieStore中
            it = response.headerIterator(SM.SET_COOKIE2);
            processCookies(it, cookieSpec, cookieOrigin, cookieStore);
        }
    }

     

     <3> 断点查看第二次请求时HttpContext对象

    通过debug可以很明显看到,HttpContext将诸多的Http请求的会话信息进行了广播。

  • 相关阅读:
    努力的一分不会少
    C语言中的数组的访问方式
    代码的规划与规范化
    Manjaro中源码安装gcc7.1
    周围都是敌人,方法总比问题多
    elementary os 0.4.1下编译GCC-7.1源码并安装成功
    C语言中的基础知识变量探讨
    19年的桌面KDE的风雨和陪伴,没有什么能够割舍
    《手把手教你学C语言》学习笔记(10)--- 程序的循环控制
    copy 的实现原理与深浅拷贝
  • 原文地址:https://www.cnblogs.com/z-qinfeng/p/11707184.html
Copyright © 2011-2022 走看看