HttpClient 是 Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,並且它支持 HTTP 協議最新的版本和建議,JAVA可以使用HttpClient的Jar包實現模擬登陸。今天嘗試登陸一下遼寧大學的選課系統。
通過頁面分析得知登陸採用Post方式,表單發送到http://jwgl.lnu.edu.cn/pls/wwwbks/bks_login2.login
,
參數名分別是stuid
和pwd
。
下面開始編寫工具類
一、實現思路
創建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完善且強大,模擬登錄還不算徹底成功,需要學習的還有很多,同時編寫代碼還不夠規範,沒有養成良好的習慣。希望可以通過寫博文徹底治癒懶癌,使自己每天進步一點點!