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請求的會話信息進行了廣播。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM