網(wǎng)上有很多的OkHttp的教程物延,但是并沒有一個(gè)是關(guān)于如何OkHttp處理重定向的。這里的處理重定向的意思是:把重定向請(qǐng)求攔截下來瘩将,然后我們自己去請(qǐng)求重定向后的網(wǎng)頁锐涯,然后通過Jsoup解析自己需要的網(wǎng)頁數(shù)據(jù)。比如說我們模擬用戶登錄嗦篱,然后自己去請(qǐng)求解析登陸后跳轉(zhuǎn)的網(wǎng)頁的內(nèi)容冰单。為什么要做這樣的一個(gè)東西呢?比如說課程表的查成績(jī)功能灸促,就可以使用這種方法來獲取成績(jī)诫欠。
大概的原理是怎樣的呢?
我們先來說一下瀏覽器是怎么樣做用戶登錄的:瀏覽器會(huì)將你輸入的帳號(hào)和密碼通過POST請(qǐng)求攜帶過去浴栽,當(dāng)然可能還會(huì)有其它字段荒叼,因?yàn)檫@個(gè)POST請(qǐng)求是我們網(wǎng)頁和服務(wù)器規(guī)定好的;登錄成功后典鸡,服務(wù)器會(huì)返回一個(gè)Set-Cookie請(qǐng)求頭字段被廓,有了Cookie瀏覽器就可以通過GET請(qǐng)求訪問登錄后的網(wǎng)頁,注意沒有這個(gè)Cookie是無法請(qǐng)求登陸后的網(wǎng)頁的椿每,GET請(qǐng)求必須設(shè)置Cookie請(qǐng)求頭字段伊者,將服務(wù)器返回的Cookie攜帶過去。
明白了瀏覽器的行為之后间护,我們知道需要做的步驟就是4步:
- 自己做POST請(qǐng)求,并且不讓它自動(dòng)重定向
- 我們拿到POST請(qǐng)求返回來的響應(yīng)挖诸,獲取對(duì)應(yīng)的Set-Cookie字段的內(nèi)容
- 將該對(duì)應(yīng)的內(nèi)容添加到GET請(qǐng)求的Cookie請(qǐng)求頭字段中汁尺,然后做GET請(qǐng)求
- 獲取到的GET請(qǐng)求的響應(yīng)體就是我們登陸后的網(wǎng)頁內(nèi)容了,如果是靜態(tài)網(wǎng)頁可以通過Jsoup解析自己想要的信息了
我們需要通過抓包或者Chorme瀏覽器自帶的請(qǐng)求查看功能來查看POST請(qǐng)求提交的表單是怎樣的多律。Chorme按F12即可
輸入帳號(hào)密碼點(diǎn)擊登錄即可
點(diǎn)擊登陸后我們可以看到痴突,控制面板出現(xiàn)了一堆訪問的記錄搂蜓,第一個(gè)就是我們要找的,第一個(gè)的Status標(biāo)志是302辽装,302是重定向的意思帮碰。我們點(diǎn)擊(pass.asp)這個(gè)請(qǐng)求,然后查看它的POST的請(qǐng)求頭(點(diǎn)擊Headers)拾积。
我們看到了一堆的Set-Cookie字段殉挽,字段對(duì)應(yīng)的內(nèi)容就是我們要攜帶做GET請(qǐng)求的
同時(shí)我們可以看到POST提交的表單內(nèi)容,有些網(wǎng)站的提交參數(shù)是經(jīng)過加密的拓巧,如果要做通用的斯碌,我們需要找到它加密的方法,做同樣的加密處理肛度。
接下來使用OkHttp進(jìn)行操作
由于OkHttp提供了自動(dòng)攜帶Cookie進(jìn)行請(qǐng)求的功能傻唾,于是我們可以很方便地進(jìn)行處理了。
final OkHttpClient client = new OkHttpClient().newBuilder()
.followRedirects(false) //禁制OkHttp的重定向操作承耿,我們自己處理重定向
.followSslRedirects(false)
.cookieJar(new LocalCookieJar()) //為OkHttp設(shè)置自動(dòng)攜帶Cookie的功能
.build();
//CookieJar是用于保存Cookie的
class LocalCookieJar implements CookieJar{
List<Cookie> cookies;
@Override
public List<Cookie> loadForRequest(HttpUrl arg0) {
if (cookies != null)
return cookies;
return new ArrayList<Cookie>();
}
@Override
public void saveFromResponse(HttpUrl arg0, List<Cookie> cookies) {
this.cookies = cookies;
}
}
為什么設(shè)置CookieJar就能自動(dòng)攜帶Cookie了呢冠骄?給你看一段OkHttp的源碼就知道了。
/**
* Populates request with defaults and cookies.
*
* <p>This client doesn't specify a default {@code Accept} header because it doesn't know what
* content types the application is interested in.
*/
private Request networkRequest(Request request) throws IOException {
Request.Builder result = request.newBuilder();
//如果CookieJar的Cookie不為空加袋,則設(shè)置Cookie字段
List<Cookie> cookies = client.cookieJar().loadForRequest(request.url());
if (!cookies.isEmpty()) {
result.header("Cookie", cookieHeader(cookies));
}
return result.build();
}
于是接下來我們就是做POST請(qǐng)求了
final OkHttpClient client = new OkHttpClient().newBuilder()
.followRedirects(false)
.followSslRedirects(false)
.cookieJar(new LocalCookieJar())
.build();
//構(gòu)造一個(gè)POST請(qǐng)求
RequestBody body = new FormBody.Builder().add("UserStyle", "student")
.add("user", "xxx").add("password", "xxx").build();
Request request = new Request.Builder().url("http://222.195.8.201/pass.asp").post(body).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
/**
* 如果不用CookieJar,那么就要自己去解析返回的Set-Cookie字段,解析之后通過addHeader("Cookie", cookie)
* 添加Cookie請(qǐng)求頭
*/
// List<String> cookies = response.headers("Set-Cookie");
// String cookie = "";
// for(int i=cookies.size()-1; i>=0; i--){
// cookie = cookie+ cookies.get(i).replace("path=/", "") + " ";
// }
//做GET請(qǐng)求
Request redirectRequest = new Request.Builder().url("http://222.195.8.201/student/asp/Select_Success.asp")
// .addHeader("Cookie", cookie)
.build();
//拿到登陸后操作的某個(gè)網(wǎng)頁的內(nèi)容
Response response2 = client.newCall(redirectRequest).execute();
String result = response2.body().string();
System.out.println(result);
}
@Override
public void onFailure(Call arg0, IOException arg1) {
}
});
拿到內(nèi)容后就可以自己進(jìn)行內(nèi)容的解析和展示了猴抹。