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,如果传的实例如果没有这两个方法那会运行出错。
packagecom.touna.httprequest;importjava.text.MessageFormat;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Set;import java.util.regex.*;importokhttp3.Cookie;importokhttp3.CookieJar;importokhttp3.FormBody;importokhttp3.HttpUrl;importokhttp3.OkHttpClient;importokhttp3.Request;importokhttp3.Response;importcom.touna.view.LogUtil;public classSession {private final OkHttpClient mOkHttpClient = new OkHttpClient.Builder().cookieJar(newCookieJarManager()).build();
//如果直接写个类,里面写saveFromResponse和loadForRequest,而不实现CookieJar接口,运行可以正常通过,但ide会显红,因为Bulider类的cookieJsr方法需要接受CookieJar类型的实例。鸭子类除了能节约代码行数,在可理解性 可读性 多人合作性上面都不如接口规范,谁知道鸭子类里面要写什么方法,除了写代码得人自己。private class CookieJarManager implementsCookieJar{private final HashMap> cookieStore = new HashMap<>();
@Overridepublic void saveFromResponse(HttpUrl url, Listcookies) {
cookieStore.put(url.host(), cookies);
}
@Overridepublic ListloadForRequest(HttpUrl url) {
List cookies =cookieStore.get(url.host());return cookies != null ? cookies : new ArrayList(){};
}
}/***@paramurl 要请求的url
*@paramparamsMap post的请求参数
*@returnpost的返回结果*/
public String post(String url, HashMapparamsMap){
LogUtil.printLog("请求的url是:" +url);
FormBody.Builder formBodyBuilder= newFormBody.Builder();
Set keySet =paramsMap.keySet();for(String key:keySet) {
String value=paramsMap.get(key);
formBodyBuilder.add(key,value);
}
FormBody formBody=formBodyBuilder.build();
Request request= newRequest
.Builder()
.post(formBody)
.url(url)
.build();try (Response response =mOkHttpClient.newCall(request).execute()) {
String respStr=response.body().string();
LogUtil.printLog("返回是: " +respStr);returnrespStr;
}catch(Exception e){
LogUtil.printLog("post失败");
e.printStackTrace();return "";
}
}publicString get(String url) {final Request.Builder builder = newRequest.Builder();
builder.url(url);final Request request =builder.build();try (Response response =mOkHttpClient.newCall(request).execute()) {returnresponse.body().string();
}catch(Exception e){
e.printStackTrace();return "";
}
}/***@parammail163Account 163邮箱账号;
*@parampasswd 邮箱密码
**/
private static voidtest163(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= newSession();
HashMap 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 dataMap = new HashMap<>() ;
dataMap.put("var","<?xml version=\"1.0\"?>1datetrue" +
"200false
"=\"topFlag\">top
truetrue");LogUtil.printLog("读取邮件列表:");
ss.post(mailListUrl,dataMap);
}
}public static voidmain(String[] args) {
test163("13148804506@163.com", "123456");
}
}
4、使用163邮箱登录,然后测试下获取邮件列表能否获取到。
测试结果,这样只要Session类的实例请求了登录接口后,就能干其他的事情了。