使用OKHttp模擬登錄知乎,兼談OKHttp中Cookie的使用!

本文主要是想和你們探討技術,讓你們學會Cookie的使用,切勿作違法之事!
java

不少Android初學者在剛開始學習的時候,或多或少都想本身搞個應用出來,把本身學的十八般武藝全都用在這個APP上,其實這個想法很好,項目驅動學習,效率更高,這是大學老師教給個人。但是一個APP,若是純粹搞成一個本地應用,會變得很沒有意思,因此咱們通常仍是作網絡應用,網絡應用涉及到網絡服務器的搭建,數據的採集等等太過於耗時,有的人可能剛剛搭建一個網絡服務器就耗費了很長時間,搞得都沒有信心學習Android了,針對這種狀況,我通常建議你們本身去抓包。抓包又會遇到新問題,就是有可能你須要模擬登錄。所以,本文以知乎登錄爲例,帶你們來看看模擬登錄,同時也來看看OKHttp中Cookie的使用問題。web

爲何選擇知乎做爲切入點呢?沒什麼,在想到這個話題的一瞬間恰好想到了知乎!數據庫

實際上模擬登錄仍是很簡單的,麻煩的是須要咱們去仔細分析請求的接口和參數!瀏覽器

本文內容主要包括如下三個方面
緩存

1.知乎登錄接口和參數分析服務器

2.模擬登錄cookie

3.Cookie持久化網絡


OK,那就開始吧!
框架

1.知乎登錄接口和參數分析

本文采用Chrome瀏覽器來進行分析,首先打開知乎登陸頁面,以下:ide

按下F12,打開Chrome的調試窗口:

而後在知乎的登陸頁面輸入用戶名和登陸密碼,注意觀察調試窗口的日誌:

在這裏咱們能夠看到傳遞給服務器的參數主要有以下四個,分別是_xsrf,password,remember_me,以及email四個,remember_me很好理解,是否記住密碼,email實際就是咱們的帳號名稱,password實際就是咱們的登陸密碼,至於_xsrf則是登陸頁面的一個隱藏域,這個數據很容易拿到,同時,從這裏咱們還能夠看出知乎登陸時請求的接口是https://www.zhihu.com/login/email

OK,分析完這些以後,咱們就能夠動手開始編碼了。

2.模擬登錄

知道了知乎在登陸的過程當中須要傳遞哪些參數以後,接下來咱們就能夠動手模擬登陸。

用戶名、密碼以及記住我這三個參數很是容易記憶,很容易獲取,以後第一個參數稍微有些麻煩,咱們打開用戶登陸頁面的源碼,會看到以下一行代碼:

這個呢其實就是隱藏域的值。好了,如今登陸所須要的四個參數都知道從哪裏獲取了,那咱們就開始登陸吧,個人登陸頁面以下:

輸入用戶名和密碼,點擊登陸按鈕就能夠執行登陸操做了,可是在執行登陸操做以前,我須要先訪問知乎的登陸頁面,拿到那個隱藏域的值。因而乎,個人登陸邏輯是這樣:

先來看如何獲取隱藏域,這裏涉及到如何解析HTML文本,我在這裏用到了Jsoup庫,對該庫不瞭解的小夥伴請自行Google,核心代碼以下(完整代碼小夥伴們自行在文末下載該Project):

Request request = new Request.Builder().url("https://www.zhihu.com/#signin").build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String resp = response.body().string();
                Document parse = Jsoup.parse(resp);
                Elements select = parse.select("input[type=hidden]");
                Element element = select.get(0);
                String xsrf = element.attr("value");
                Message msg = mHandler.obtainMessage();
                msg.what = 1;
                msg.obj = xsrf;
                Log.d("google_lenve_fb", "onResponse: xsrf:" + xsrf);
                mHandler.sendMessage(msg);
            }
        });

在下載到該HTML文本以後,先將該文本轉爲一個Document對象,而後使用select選擇器,找到有一個屬性爲type=hidden的input節點,而後獲取該節點中的value屬性,那麼毫無疑問,該value屬性,就是咱們要得_xsrf的值。有了這個值以後,接下來訪問登陸頁面便可登陸成功,代碼以下:

FormBody formBody = new FormBody.Builder()
                .add("captcha_type", "cn")
                .add("_xsrf", xsrf)
                .add("password", passwordEt.getText().toString())
                .add("remember_me", "true")
                .add("email", usernameEt.getText().toString())
                .build();
        Request request = new Request.Builder().post(formBody).url(loginUrl).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.d("google_lenve_fb", "onResponse: " + response.body().string().toString());
            }
        });

登陸成功以後,知乎會返回以下一行Json:

{
    "r":0,
    "msg":"登陸成功"
}

至此爲止,咱們的模擬登陸就成功了,是否是很簡單!!!


但是單純的模擬登陸並無什麼意義,舉個栗子,咱們知道要想獲取用戶的私信,必須是登陸狀態才能獲取,在知乎中獲取用戶私信的頁面地址是:

https://www.zhihu.com/inbox

但是即便你模擬登陸成功了,仍是沒法獲取這個頁面的信息,當你訪問這個頁面的時候,系統會自動跳轉到登陸頁面,由於系統並不知道你已經登陸了。那麼我該怎麼作,才能讓系統知道我已經登陸成功了呢?這裏就涉及到Cookie。

3.Cookie持久化

Cookie這個東西最先由網景的員工在1994年提出,他在他的原始說明文檔中解釋了Cookie工做原理的基本信息,該文本後來被做爲規範歸入到RFC 2965中,網景瀏覽器從一開始就支持Cookie,現現在全部的Web瀏覽器都支持Cookie。那麼Cookie究竟是什麼?其實就是瀏覽器存儲在用戶電腦上的一小段文本,該文本從何而來?在用戶首次登陸的時候,服務器會返回一段Cooike文本,瀏覽器將該文本存入到用戶的電腦中,之後每當用戶向該服務器發起網絡請求時,瀏覽器都會攜帶上這段文本,這樣服務器就知道該用戶是否已經登陸過了。

OK,上文是咱們對Cookie一個簡單的介紹,接下來咱們就來看看在咱們的OkHttp中如何實現Cookie的緩存。

OkHttp框架從3.0開始簡化了Cookie的使用,它提供了一個叫作cookieJar的API,只須要咱們實現該API中的方法便可,一個簡單的使用方式以下:

builder = new OkHttpClient.Builder();
builder.cookieJar(new CookieJar() {
    private final HashMap<String, List<Cookie>> cookieStore = new HashMap<String, List<Cookie>>();

    @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>();
    }
});
okHttpClient = builder.build();

該接口中有兩個回調方法,一個是保存Cookie,一個是讀取Cookie,我將Cookie存儲在一個HashMap中,存儲和讀取都在這個HashMap中操做。設置了Cookie以後,當我再次登陸,登陸成功以後獲取私信時就沒有任何問題了。但是存在Map中的東東一旦個人應用退出以後,這個東西就又沒了,再次進來仍是要登陸,那麼有什麼辦法能夠實現Cookie的持久化呢?固然能夠。Cookie持久化,你能夠將Cookie保存 在數據庫中,也能夠將Cookie保存在SharedPreferences中,都行,我這裏以保存在SharedPreferences中,具體代碼參考AsyncHttpClient相關類,代碼較長,我這裏就不貼了,你們能夠在文本下載Project,Cookie持久化使用方式以下:

builder = new OkHttpClient.Builder();
CookieJarImpl cookieJarImpl = new CookieJarImpl(new PersistentCookieStore(getApplicationContext()));
builder.cookieJar(cookieJarImpl);
okHttpClient = builder.build();

將Cookie持久化到本地以後,接下來我就能夠在登陸成功過一次以後,不斷的獲取私信內容了,若是用戶想退出登陸,只須要將SharedPreferences中的Cookie信息刪除便可,簡單吧!


本文所涉及到的工程下載http://download.csdn.net/detail/u012702547/9599322

相關文章
相關標籤/搜索