1.HttpClient
Android SDK中包含了HttpClient,在Android6.0版本直接刪除了HttpClient類庫,如果想使用解決方法
是在android studio相應的module下的build.gradle中加入
android {
useLibrary 'org.apache.http.legacy'
}
HttpClient的GET請求
先用DefaultHttpClient類來實例化一個HttpClient,並配置好默認的請求參數:
//創建HttpClient
private HttpClient createHttpClient() {
HttpParams mDefaultHttpParams = new BasicHttpParams();
//設置連接超時
HttpConnectionParams.setConnectionTimeout(mDefaultHttpParams, 10000);
//設置請求超時
HttpConnectionParams.setSoTimeout(mDefaultHttpParams, 10000);
HttpConnectionParams.setTcpNoDelay(mDefaultHttpParams, true);
HttpProtocolParams.setVersion(mDefaultHttpParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(mDefaultHttpParams, HTTP.UTF_8);
//持續握手
HttpProtocolParams.setUseExpectContinue(mDefaultHttpParams, true);
HttpClient mHttpClient = new DefaultHttpClient(mDefaultHttpParams);
return mHttpClient;
}
然後創建HttpGet和HttpClient,請求網絡並得到HttpResponse,並對HttpResponse進行處理:
private void useHttpClientGet(String url) {
HttpGet mHttpGet = new HttpGet(url);
mHttpGet.addHeader("Connection", "Keep-Alive");
try {
HttpClient mHttpClient = createHttpClient();
HttpResponse mHttpResponse = mHttpClient.execute(mHttpGet);
HttpEntity mHttpEntity = mHttpResponse.getEntity();
int code = mHttpResponse.getStatusLine().getStatusCode();
if (null != mHttpEntity) {
InputStream mInputStream = mHttpEntity.getContent();
String respose = converStreamToString(mInputStream);
Log.i("wangshu", "請求狀態碼:" + code + "\n請求結果:\n" + respose);
mInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
converStreamToString方法將請求結果轉換成String類型:
private String converStreamToString(InputStream is) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuffer sb = new StringBuffer();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
String respose = sb.toString();
return respose;
}
最後我們開啓線程訪問百度:
new Thread(new Runnable() {
@Override
public void run() {
useHttpClientGet("http://www.baidu.com");
}
}).start();
請求的返回結果,請求狀態碼爲200,結果就是個html頁。
GET請求的參數暴露在URL中,這有些不大妥當,而且URL的長度也有限制:長度在2048字符之內,在HTTP 1.1後URL長度纔沒有限制。一般情況下POST可以替代GET,接下來我們來看看HttpClient的POST請求。
HttpClient的POST請求
post請求和get類似就是需要配置要傳遞的參數:
private void useHttpClientPost(String url) {
HttpPost mHttpPost = new HttpPost(url);
mHttpPost.addHeader("Connection", "Keep-Alive");
try {
HttpClient mHttpClient = createHttpClient();
List<NameValuePair> postParams = new ArrayList<>();
//要傳遞的參數
postParams.add(new BasicNameValuePair("username", "moon"));
postParams.add(new BasicNameValuePair("password", "999"));
mHttpPost.setEntity(new UrlEncodedFormEntity(postParams));
HttpResponse mHttpResponse = mHttpClient.execute(mHttpPost);
HttpEntity mHttpEntity = mHttpResponse.getEntity();
int code = mHttpResponse.getStatusLine().getStatusCode();
if (null != mHttpEntity) {
InputStream mInputStream = mHttpEntity.getContent();
String respose = converStreamToString(mInputStream);
Log.i("wangshu", "請求狀態碼:" + code + "\n請求結果:\n" + respose);
mInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.HttpURLConnection
Android 2.2版本之前,HttpURLConnection一直存在着一些令人厭煩的bug。比如說對一個可讀的InputStream調用close()方法時,就有可能會導致連接池失效了。那麼我們通常的解決辦法就是直接禁用掉連接池的功能:
private void disableConnectionReuseIfNecessary() {
// 這是一個2.2版本之前的bug
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}
所以在Android 2.2版本以及之前的版本使用HttpClient是較好的選擇,而在Android 2.3版本及以後,HttpURLConnection則是最佳的選擇,它的API簡單,體積較小,因而非常適用於Android項目。壓縮和緩存機制可以有效地減少網絡訪問的流量,在提升速度和省電方面也起到了較大的作用。另外在Android 6.0版本中,HttpClient庫被移除了,HttpURLConnection則是以後我們唯一的選擇。
HttpURLConnection的POST請求
因爲會了HttpURLConnection的POST請求那GET請求也就會了,所以我這裏只舉出POST的例子
首先我們創建一個UrlConnManager類,然後裏面提供getHttpURLConnection()方法用於配置默認的參數並返回HttpURLConnection:
public static HttpURLConnection getHttpURLConnection(String url){
HttpURLConnection mHttpURLConnection=null;
try {
URL mUrl=new URL(url);
mHttpURLConnection=(HttpURLConnection)mUrl.openConnection();
//設置鏈接超時時間
mHttpURLConnection.setConnectTimeout(15000);
//設置讀取超時時間
mHttpURLConnection.setReadTimeout(15000);
//設置請求參數
mHttpURLConnection.setRequestMethod("POST");
//添加Header
mHttpURLConnection.setRequestProperty("Connection","Keep-Alive");
//接收輸入流
mHttpURLConnection.setDoInput(true);
//傳遞參數時需要開啓
mHttpURLConnection.setDoOutput(true);
} catch (IOException e) {
e.printStackTrace();
}
return mHttpURLConnection ;
}
因爲我們要發送POST請求,所以在UrlConnManager類中再寫一個postParams()方法用來組織一下請求參數並將請求參數寫入到輸出流中:
public static void postParams(OutputStream output,List<NameValuePair>paramsList) throws IOException{
StringBuilder mStringBuilder=new StringBuilder();
for (NameValuePair pair:paramsList){
if(!TextUtils.isEmpty(mStringBuilder)){
mStringBuilder.append("&");
}
mStringBuilder.append(URLEncoder.encode(pair.getName(),"UTF-8"));
mStringBuilder.append("=");
mStringBuilder.append(URLEncoder.encode(pair.getValue(),"UTF-8"));
}
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(output,"UTF-8"));
writer.write(mStringBuilder.toString());
writer.flush();
writer.close();
}
接下來我們添加請求參數,調用postParams()方法將請求的參數組織好傳給HttpURLConnection的輸出流,請求連接並處理返回的結果:
private void useHttpUrlConnectionPost(String url) {
InputStream mInputStream = null;
HttpURLConnection mHttpURLConnection = UrlConnManager.getHttpURLConnection(url);
try {
List<NameValuePair> postParams = new ArrayList<>();
//要傳遞的參數
postParams.add(new BasicNameValuePair("username", "moon"));
postParams.add(new BasicNameValuePair("password", "123"));
UrlConnManager.postParams(mHttpURLConnection.getOutputStream(), postParams);
mHttpURLConnection.connect();
mInputStream = mHttpURLConnection.getInputStream();
int code = mHttpURLConnection.getResponseCode();
String respose = converStreamToString(mInputStream);
Log.i("wangshu", "請求狀態碼:" + code + "\n請求結果:\n" + respose);
mInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
最後開啓線程請求網絡:
private void useHttpUrlConnectionGetThread() {
new Thread(new Runnable() {
@Override
public void run() {
useHttpUrlConnectionPost("http://www.baidu.com");
}
}).start();
}
Fiddler和HTTP協議分析的請查看HTTP協議分析。