HttpClient模擬Post實現登錄遼大教務處

HttpClient 是 Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,並且它支持 HTTP 協議最新的版本和建議,JAVA可以使用HttpClient的Jar包實現模擬登陸。今天嘗試登陸一下遼寧大學的選課系統。

這裏寫圖片描述

通過頁面分析得知登陸採用Post方式,表單發送到http://jwgl.lnu.edu.cn/pls/wwwbks/bks_login2.login
參數名分別是stuidpwd
下面開始編寫工具類

一、實現思路

創建HttpClient默認實例

CloseableHttpClient httpClient = HttpClients.createDefault();

創建HttpPost實例

HttpPost httpPost = new HttpPost(URL);

如果是Get方法則創建HttpGet實例,二者構造函數參數都可以爲目標地址。

創建HttpEntity實例:

StringEntity stringEntity = new StringEntity(param, "UTF-8");
stringEntity.setContentType("application/x-www-form-urlencoded");

Http消息(請求或者響應)會攜有Http實體,Http實體可以解析爲文本形式,也可以將文本轉換爲Http實體,無論解析還是轉換都要約定字符編碼。

Post請求的參數也可以被寫入Http實體中,其格式爲:

key1=value1&key2=value2

ContentType內容類型,用於定義網絡文件的類型和網頁的編碼,決定文件接收方將以什麼形式、什麼編碼讀取這個文件,通常Post表單內容類型默認爲application/x-www-form-urlencoded

更多內容類型參照:

HTTP Content-type 對照表
http://tool.oschina.net/commons

創建RequstConfig實例:

RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(15000)
                    .setConnectTimeout(15000)
                    .setConnectionRequestTimeout(15000)
                    .build();

通常利用requestConfig設置超時時間。

將配置好的HttpEntity與RequestConfig實例設置到HttpPost

httpPost.setEntity(stringEntity);
httpPost.setConfig(requestConfig);

用HttpClient實例執行HttpPost,返回Response。

CloseableHttpResponse response = httpClient.execute(httpPost);

httpClient.execute()方法也適用於HttpGet,會返回一個CloseableHttpResponse對象,裏面封裝有HttpEntity

從Response獲取Entity,得到訪問信息

我們可以通過response實例中的getEntity()方法獲得httpEntity

HttpEntity httpEntity = response.getEntity();

如果想得到網頁源文件,則利用EntityUtils.toString()將實體解析成字符串。

String responseContent = EntityUtils.toString(httpEntity , "UTF-8");

關閉資源

response.close();
httpClient.close();

完整源碼

package test;

import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.util.EntityUtils;

public class FunctionClass {
    /**
     * sendPost 發送post請求
     * @param url
     * @param param
     * @return
     * @throws IOException
     */
    public String sendPost(String url, String param) throws IOException {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;

        try {
            HttpPost hp = new HttpPost(url);

            //配置ResquestConfig
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(15000)
                    .setConnectTimeout(15000)
                    .setConnectionRequestTimeout(15000)
                    .build();

            //配置StringEntity
            StringEntity stringEntity = new StringEntity(param, "UTF-8");
            stringEntity.setContentType("application/x-www-form-urlencoded");

            //將Entity和Config設置到HttpPost
            hp.setEntity(stringEntity);
            hp.setConfig(requestConfig);

            //獲取頁面
            response = httpClient.execute(hp);
            result = EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();// TODO: handle exception
        }finally{
            httpClient.close();
            response.close();
        }
        return result;
    }
}

二、測試一下

編寫測試類

package test;

import java.io.IOException;

public class TestClass {

    public static void main(String[] args) {
        //http://jwgl.lnu.edu.cn/pls/wwwbks/bks_login2.login?stuid=161407212&pwd=058512
        FunctionClass fc = new FunctionClass();
        try {
            String result = fc.sendPost("http://jwgl.lnu.edu.cn/pls/wwwbks/bks_login2.login", "stuid=XXXXXX&pwd=YYYYY");
            System.out.println("返回的結果是:");
            System.out.println(result);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

運行調試

運行發現出現了問題

這裏寫圖片描述

並沒有返回正確的頁面信息,而僅僅返回一個換行符,讓我們來通過response的getStatusLine()方法看一下問題出在哪裏。

System.out.println(response.getStatusLine());

這裏寫圖片描述

原來這裏出現了302 Found錯誤。

三、302 Found

關於302 Found:

302 Found 是HTTP協議中的一個狀態碼(Status Code),可以簡單的理解爲該資源原本確實存在,但已經被臨時改變了位置;或者換個說法,就是臨時的存在於某個臨時URL下。

也就是說Servlet可能發生了重定向,通常Get或者Head會自動轉向重定向的網頁,但是Post和Push方法是被禁止的。

解決方案

其中一個辦法是採用Get方法代替Post,但是Get和Post本身就是兩個東西,不是所有網頁都可以這樣。
第二個方法是改變HttpClient的重定向策略

CloseableHttpClient httpClient = HttpClients.createDefault();

改爲

CloseableHttpClient httpClient = HttpClients.custom()
                .setRedirectStrategy(new LaxRedirectStrategy())
                .build();

LaxRedirectStrategy可實現HEAD, GET, POST, 和DELETE方法自動重定向,可以藉此解除HTTP規定的對POST方法自動重定向的限制

第二次運行調試

這裏寫圖片描述

已經可以登錄成功,並且爭取獲取頁面源文件了,初步戰略目標達成。

三、總結與反思

HttpClient完善且強大,模擬登錄還不算徹底成功,需要學習的還有很多,同時編寫代碼還不夠規範,沒有養成良好的習慣。希望可以通過寫博文徹底治癒懶癌,使自己每天進步一點點!

發佈了34 篇原創文章 · 獲贊 21 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章