URLConnection是個抽象類租幕,它有兩個直接子類分別是HttpURLConnection和JarURLConnection闯狱。另外一個重要的類是URL辆飘,通常URL可以通過傳給構(gòu)造器一個String類型的參數(shù)來生成一個指向特定地址的URL實例咕晋。
每個 HttpURLConnection 實例都可用于生成單個請求趁矾,但是其他實例可以透明地共享連接到 HTTP 服務器的基礎(chǔ)網(wǎng)絡。請求后在 HttpURLConnection 的 InputStream 或 OutputStream 上調(diào)用 close() 方法可以釋放與此實例關(guān)聯(lián)的網(wǎng)絡資源槽袄,但對共享的持久連接沒有任何影響。如果在調(diào)用 disconnect() 時持久連接空閑锋谐,則可能關(guān)閉基礎(chǔ)套接字遍尺。
需求,發(fā)起一個Post請求涮拗,并攜帶參數(shù)給服務器乾戏,服務器返回Json數(shù)據(jù)
代碼實現(xiàn)
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
/**
* Created by yuandl on 2016-10-18.
* HttpURLConnection測試
*/
public class URLConnectionTest {
public static void main(String[] args) {
String url = "http://10.58.178.72/intco/mobi/member/login";
HashMap<String, String> params = new HashMap<>();
params.put("username", "13468857714");
params.put("pwd", MD5.md5("123456").toLowerCase());
requestPost(url, params);
}
/**
* Post請求
*
* @param httpUrl
* @param paramsMap
*/
private static void requestPost(String httpUrl, HashMap<String, String> paramsMap) {
try {
String baseUrl = httpUrl;
//合成參數(shù)
StringBuilder tempParams = new StringBuilder();
int pos = 0;
for (String key : paramsMap.keySet()) {
if (pos > 0) {
tempParams.append("&");
}
tempParams.append(String.format("%s=%s", key, URLEncoder.encode(paramsMap.get(key), "utf-8")));
pos++;
}
String params = tempParams.toString();
System.out.println("Post方式請求地址httpUrl--->" + params);
System.out.println("Post方式請求參數(shù)params--->" + params);
// 請求的參數(shù)轉(zhuǎn)換為byte數(shù)組
byte[] postData = params.getBytes();
// 新建一個URL對象
URL url = new URL(baseUrl);
// 打開一個HttpURLConnection連接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 設置連接超時時間
urlConn.setConnectTimeout(5 * 1000);
//設置從主機讀取數(shù)據(jù)超時
urlConn.setReadTimeout(5 * 1000);
// Post請求必須設置允許輸出 默認false
urlConn.setDoOutput(true);
//設置請求允許輸入 默認是true
urlConn.setDoInput(true);
// Post請求不能使用緩存
urlConn.setUseCaches(false);
// 設置為Post請求
urlConn.setRequestMethod("POST");
//設置本次連接是否自動處理重定向
urlConn.setInstanceFollowRedirects(true);
// 配置請求Content-Type
urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 開始連接
urlConn.connect();
// 發(fā)送請求參數(shù)
DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
dos.write(postData);
dos.flush();
dos.close();
// 判斷請求是否成功
if (urlConn.getResponseCode() == 200) {
// 獲取返回的數(shù)據(jù)
String result = streamToString(urlConn.getInputStream());
System.out.println("Post方式請求成功迂苛,result--->" + result);
} else {
System.out.println("Post方式請求失敗");
}
// 關(guān)閉連接
urlConn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 將輸入流轉(zhuǎn)換成字符串
*
* @param is 從網(wǎng)絡獲取的輸入流
* @return
*/
public static String streamToString(InputStream is) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
is.close();
byte[] byteArray = baos.toByteArray();
return new String(byteArray);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
- 打印結(jié)果
Post方式請求地址httpUrl--->pwd=e10adc3949ba59abbe56e057f20f883e&username=13468857714
Post方式請求參數(shù)params--->pwd=e10adc3949ba59abbe56e057f20f883e&username=13468857714
Post方式請求成功,result--->{"status":1,"data":{"mId":"426e743224db4ecb8313e069982a7496","mName":"*東亮","pwd":"f241426298243cb7f6f97da58749ffb386c1457d","sex":"1","mobile":"13468857714","authentication":"0","personal":"0","isMain":"1","parentId":"0","newOrold":"1","imgurl":"http://10.58.178.72/intco/upload/img/member/portrait/2016/10/9331f754fbb742d99f6e61dcee0fe61d.jpg","state":"1","rongcloud_token":"1XHoYMAzlXidThqzyftV8at+qlfSNm8M8gqvzen0AUEV4lvsXAvmBJF0GQBkh5JP1I3XDUvd60sWEglC4+KRsnv5d+pcovzErw8ekgl7y6fM3gYaOuFDcqN0iaV2F2PAOM4jDTjH9M8="},"msg":"登錄成功鼓择!"}
- 總結(jié)
- HttpURLConnection的connect()函數(shù)三幻,實際上只是建立了一個與服務器的tcp連接,并沒有實際發(fā)送http請求呐能。 無論是post還是get念搬,http請求實際上直到HttpURLConnection的getInputStream()這個函數(shù)里面才正式發(fā)送出去。
- 在用POST方式發(fā)送URL請求時摆出,URL請求參數(shù)的設定順序是重中之重朗徊, 對connection對象的一切配置(那一堆set函數(shù)) 都必須要在connect()函數(shù)執(zhí)行之前完成。而對outputStream的寫操作偎漫,又必須要在inputStream的讀操作之前爷恳。 這些順序?qū)嶋H上是由http請求的格式?jīng)Q定的。
- http請求實際上由兩部分組成象踊, 一個是http頭温亲,所有關(guān)于此次http請求的配置都在http頭里面定義, 一個是正文content杯矩。 connect()函數(shù)會根據(jù)HttpURLConnection對象的配置值生成http頭部信息栈虚,因此在調(diào)用connect函數(shù)之前, 就必須把所有的配置準備好菊碟。
- 在http頭后面緊跟著的是http請求的正文节芥,正文的內(nèi)容是通過outputStream流寫入的,實際上outputStream不是一個網(wǎng)絡流逆害,充其量是個字符串流头镊,往里面寫入的東西不會立即發(fā)送到網(wǎng)絡, 而是存在于內(nèi)存緩沖區(qū)中魄幕,待outputStream流關(guān)閉時相艇,根據(jù)輸入的內(nèi)容生成http正文。 至此纯陨,http請求的東西已經(jīng)全部準備就緒坛芽。在getInputStream()函數(shù)調(diào)用的時候,就會把準備好的http請求 正式發(fā)送到服務器了翼抠,然后返回一個輸入流咙轩,用于讀取服務器對于此次http請求的返回信息。由于http 請求在getInputStream的時候已經(jīng)發(fā)送出去了(包括http頭和正文)阴颖,因此在getInputStream()函數(shù) 之后對connection對象進行設置(對http頭的信息進行修改)或者寫入outputStream(對正文進行修改) 都是沒有意義的了活喊,執(zhí)行這些操作會導致異常的發(fā)生。
- 分析
HttpURLConnection是Java層提供的標準網(wǎng)絡請求工具類量愧,可以實現(xiàn)各種功能钾菊。通過以上的代碼和返回的請求結(jié)果可以知道帅矗,我們知道其實在Android中無論什么網(wǎng)絡請求框架,最底層也是這樣去實現(xiàn)的煞烫。我們可以在這個上面繼續(xù)封裝浑此,不斷完善就可以成為一個輕量級的Android網(wǎng)絡請求框架。