java 實現類似於python requests包的Session類,自動管理cookie。


1、在py中requests.post()和get()函數都是在那個函數內部里面自動生成了一個Session類的實例,所以requests,post和get函數要想干登陸后才能干的事情,需要添加cookie或者把cookie寫在headers里面,要想自動管理cookie,就不能每次請求都實例化一個新的Session類的對象了,需要直接實例化Session類,然后使用該實例,而不是使用那兩個函數。

py的Session類的使用方法是:

ss = requests.Session()

ss.post(login_url,data = {"username":"xiaomin", "password":"123456"})

ss.get(some_url)

 

2、java的OkHttp3默認是不自動管理cookie。

 

默認是使用NIO_COOKIES

 

 

 3、實現cookie自動管理,需要在OkhttpClient類的Builder類中的cookieJar方法傳入CookieJar實例。

 

 實現CookieJar接口中的saveFromResponse 和loadForRequest方法,把cookie保存到haspmap中,讀取也是從hashmap中,這樣就實現自動管理cookie。如果要保持代碼重啟還能持久化cookie管理可以使用redis  sqllite 或者實現Serializable,序列化cookie到文件。

okhttp3.internal.http.BridgeInterceptor;
okhttp3.internal.http.HttpHeaders;
為什么實現了CookieJar這兩個文件中會調用傳進去的實例的這兩個方法,根據了請求的url的域名,把cookie添加到request的header了,返回時候從header里面保存cookie,如果傳的實例如果沒有這兩個方法那會運行出錯。

 

 

 

 

package com.touna.httprequest;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.regex.*;

import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import com.touna.view.LogUtil;



public class Session {

    private final OkHttpClient mOkHttpClient = new OkHttpClient.Builder().cookieJar(new CookieJarManager()).build();  
   //如果直接寫個類,里面寫saveFromResponse和loadForRequest,而不實現CookieJar接口,運行可以正常通過,但ide會顯紅,因為Bulider類的cookieJsr方法需要接受CookieJar類型的實例。鴨子類除了能節約代碼行數,在可理解性 可讀性 多人合作性上面都不如接口規范,誰知道鴨子類里面要寫什么方法,除了寫代碼得人自己。
private class CookieJarManager implements CookieJar{ private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>(); @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { cookieStore.put(url.host(), cookies); } @Override public List<Cookie> loadForRequest(HttpUrl url) { List<Cookie> cookies = cookieStore.get(url.host()); return cookies != null ? cookies : new ArrayList<Cookie>(){}; } } /** * @param url 要請求的url * @param paramsMap post的請求參數 * @return post的返回結果 */ public String post(String url, HashMap<String, String > paramsMap){ LogUtil.printLog("請求的url是:" + url); FormBody.Builder formBodyBuilder = new FormBody.Builder(); Set<String> keySet = paramsMap.keySet(); for(String key:keySet) { String value = paramsMap.get(key); formBodyBuilder.add(key,value); } FormBody formBody = formBodyBuilder.build(); Request request = new Request .Builder() .post(formBody) .url(url) .build(); try (Response response = mOkHttpClient.newCall(request).execute()) { String respStr = response.body().string(); LogUtil.printLog("返回是: " + respStr); return respStr; }catch (Exception e){ LogUtil.printLog("post失敗"); e.printStackTrace(); return ""; } } public String get(String url) { final Request.Builder builder = new Request.Builder(); builder.url(url); final Request request = builder.build(); try (Response response = mOkHttpClient.newCall(request).execute()) { return response.body().string(); }catch (Exception e){ e.printStackTrace(); return ""; } } /** * @param mail163Account 163郵箱賬號; * @param passwd 郵箱密碼 * */ private static void test163(String mail163Account, String passwd){ String loginUrl = MessageFormat.format("https://mail.163.com/entry/cgi/ntesdoor?funcid=loginone&language=-1&passtype=1" + "&iframe=1&product=mail163&from=web&df=email163&race=-2_262_-2_hz&module=&uid={0}&style=-1&net=t&skinid=null",mail163Account); Session ss = new Session(); HashMap<String,String> paramsMap = new HashMap<>() ; paramsMap.put("username",mail163Account); paramsMap.put("url2","http://email.163.com/errorpage/error163.htm"); paramsMap.put("savalogin","0"); paramsMap.put("password",passwd); String respStr = ss.post(loginUrl,paramsMap); //登錄 Pattern sidPattern = Pattern.compile("sid=(.*)&"); Matcher m = sidPattern.matcher(respStr); if (!m.find()){ LogUtil.printLog("登錄失敗"); }else{ String sid = m.group(1); LogUtil.printLog(sid); String mailListUrl = MessageFormat.format("https://mail.163.com/js6/s?sid={0}&func=mbox:listMessages",sid); HashMap<String,String> dataMap = new HashMap<>() ; dataMap.put("var","<?xml version=\"1.0\"?><object><int name=\"fid\">1</int><string name=\"order\">date</string><boolean name=\"desc\">true" + "</boolean><int name=\"limit\">20</int><int name=\"start\">0</int><boolean name=\"skipLockedFolders\">false</boolean><string name" + "=\"topFlag\">top</string><boolean name=\"returnTag\">true</boolean><boolean name=\"returnTotal\">true</boolean></object>"); LogUtil.printLog("讀取郵件列表:"); ss.post(mailListUrl,dataMap); } } public static void main(String[] args) { test163("13148804506@163.com", "123456"); } }

 

4、使用163郵箱登錄,然后測試下獲取郵件列表能否獲取到。

測試結果,這樣只要Session類的實例請求了登錄接口后,就能干其他的事情了。

 


免責聲明!

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



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