原文:https://jasonzhong.github.io/2017/01/26/Android-%E6%B5%85%E6%9E%90-HttpURLConnection/
前言
Linus Benedict Torvalds : RTFSC – Read The Funning Source Code
概述
HttpURLConnection是一種多用途、輕量極的HTTP客戶端,使用它來進(jìn)行HTTP操作可以適用于大多數(shù)的應(yīng)用程序傅瞻。
HttpURLConnection相對于HttpClient的優(yōu)點(diǎn):
HttpURLConnection | HttpClient |
---|---|
Android SDK的標(biāo)準(zhǔn)實(shí)現(xiàn) | apache的開源實(shí)現(xiàn) |
支持GZIP壓縮 | 也支持GZIP壓縮触创,但處理 |
支持系統(tǒng)級連接池,即打開的連接不會直接關(guān)閉,在一段時間內(nèi)所有程序可共用 | 不如官方直接系統(tǒng)底層支持好 |
在系統(tǒng)層面做了緩存策略處理,加快重復(fù)請求的速度 | 無 |
使用
使用這個類應(yīng)該跟從以下步驟:
Step 1
Obtain a new HttpURLConnection by calling URL.openConnection() and casting the result to HttpURLConnection. 獲得一個新的HttpURLConnection類應(yīng)該調(diào)用URL.openConnection()
并且將結(jié)果強(qiáng)轉(zhuǎn)成HttpURLConnection
類照藻。
Step 2
Prepare the request. The primary property of a request is its URI. Request headers may also include metadata such as credentials, preferred content types, and session cookies.準(zhǔn)備一個request
免钻。這個request主要屬性是它的URI彼水。Request的頭部將會包含一些元數(shù)據(jù)例如憑證,首選內(nèi)容類型和會話Cookie极舔。
Step 3
Optionally upload a request body. Instances must be configured with setDoOutput(true) if they include a request body. Transmit data by writing to the stream returned by getOutputStream().可選上傳的request內(nèi)容凤覆。如果它包含一個request內(nèi)容,實(shí)例必須配置為setDoOutput(true)
拆魏。通過寫入getOutputStream()返回的流來傳輸數(shù)據(jù)盯桦。
Step 4
Read the response. Response headers typically include metadata such as the response body's content type and length, modified dates and session cookies. The response body may be read from the stream returned by getInputStream(). If the response has no body, that method returns an empty stream.讀取響應(yīng)。響應(yīng)標(biāo)頭通常包括元數(shù)據(jù)稽揭,例如響應(yīng)正文的內(nèi)容類型和長度,修改日期和會話Cookie肥卡。 響應(yīng)主體可以從getInputStream()返回的流中讀取溪掀。 如果響應(yīng)沒有正文,那么該方法將返回一個空流步鉴。
Step 5
Disconnect. Once the response body has been read, the HttpURLConnection should be closed by calling disconnect(). Disconnecting releases the resources held by a connection so they may be closed or reused.斷開鏈接揪胃。一旦響應(yīng)內(nèi)容被讀取,HttpURLConnection
應(yīng)該要被關(guān)閉用disconnect()
函數(shù)氛琢。斷開連接釋放連接持有的資源喊递,以便它們可以被關(guān)閉或重用。
例子
URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
readStream(in);
} finally {
urlConnection.disconnect();
}
返回值
類型 | 鍵值 |
---|---|
HTTP_ACCEPTED | HTTP Status-Code 202: Accepted. |
HTTP_BAD_GATEWAY | HTTP Status-Code 502: Bad Gateway. |
HTTP_BAD_METHOD | HTTP Status-Code 405: Method Not Allowed. |
HTTP_BAD_REQUEST | HTTP Status-Code 400: Bad Request. |
HTTP_CLIENT_TIMEOUT | HTTP Status-Code 408: Request Time-Out. |
HTTP_CONFLICT | HTTP Status-Code 409: Conflict. |
HTTP_CREATED | HTTP Status-Code 201: Created. |
HTTP_ENTITY_TOO_LARGE | HTTP Status-Code 413: Request Entity Too Large. |
HTTP_FORBIDDEN | HTTP Status-Code 403: Forbidden. |
HTTP_GATEWAY_TIMEOUT | HTTP Status-Code 504: Gateway Timeout. |
HTTP_GONE | HTTP Status-Code 410: Gone. |
HTTP_INTERNAL_ERROR | HTTP Status-Code 500: Internal Server Error. |
HTTP_LENGTH_REQUIRED | HTTP Status-Code 411: Length Required. |
HTTP_MOVED_PERM | HTTP Status-Code 301: Moved Permanently. |
HTTP_MOVED_TEMP | HTTP Status-Code 302: Temporary Redirect. |
HTTP_MULT_CHOICE | HTTP Status-Code 300: Multiple Choices. |
HTTP_NOT_ACCEPTABLE | HTTP Status-Code 406: Not Acceptable. |
HTTP_NOT_AUTHORITATIVE | HTTP Status-Code 203: Non-Authoritative Information. |
HTTP_NOT_FOUND | HTTP Status-Code 404: Not Found. |
HTTP_NOT_IMPLEMENTED | HTTP Status-Code 501: Not Implemented. |
HTTP_NOT_MODIFIED | HTTP Status-Code 304: Not Modified. |
HTTP_NO_CONTENT | HTTP Status-Code 204: No Content. |
HTTP_OK | HTTP Status-Code 200: OK. |
HTTP_PARTIAL | HTTP Status-Code 206: Partial Content. |
HTTP_PAYMENT_REQUIRED | HTTP Status-Code 402: Payment Required. |
HTTP_PRECON_FAILED | HTTP Status-Code 412: Precondition Failed. |
HTTP_PROXY_AUTH | HTTP Status-Code 407: Proxy Authentication Required. |
HTTP_REQ_TOO_LONG | HTTP Status-Code 414: Request-URI Too Large. |
HTTP_RESET | HTTP Status-Code 205: Reset Content. |
HTTP_SEE_OTHER | HTTP Status-Code 303: See Other. |
HTTP_SERVER_ERROR | This constant was deprecated in API level 1. it is misplaced and shouldn't have existed. |
HTTP_UNAUTHORIZED | HTTP Status-Code 401: Unauthorized. |
HTTP_UNAVAILABLE | HTTP Status-Code 503: Service Unavailable. |
HTTP_UNSUPPORTED_TYPE | HTTP Status-Code 415: Unsupported Media Type. |
HTTP_USE_PROXY | HTTP Status-Code 305: Use Proxy. |
HTTP_VERSION | HTTP Status-Code 505: HTTP Version Not Supported. |
針對鏈接的屬性一些定義:
詳細(xì)使用
Get操作
private void requestGet(HashMap<String, String> paramsMap) {
try {
String baseUrl = "https://baidu.com/";
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 requestUrl = baseUrl + tempParams.toString();
// 新建一個URL對象
URL url = new URL(requestUrl);
// 打開一個HttpURLConnection連接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 設(shè)置連接主機(jī)超時時間
urlConn.setConnectTimeout(5 * 1000);
// 設(shè)置從主機(jī)讀取數(shù)據(jù)超時
urlConn.setReadTimeout(5 * 1000);
// 設(shè)置是否使用緩存 默認(rèn)是true
urlConn.setUseCaches(true);
// 設(shè)置為Post請求
urlConn.setRequestMethod("GET");
// urlConn設(shè)置請求頭信息
// 設(shè)置請求中的媒體類型信息阳似。
urlConn.setRequestProperty("Content-Type", "application/json");
// 設(shè)置客戶端與服務(wù)連接類型
urlConn.addRequestProperty("Connection", "Keep-Alive");
// 開始連接
urlConn.connect();
// 判斷請求是否成功
if (urlConn.getResponseCode() == 200) {
// 獲取返回的數(shù)據(jù)
String result = streamToString(urlConn.getInputStream());
Log.e(TAG, "Get方式請求成功骚勘,result--->" + result);
} else {
Log.e(TAG, "Get方式請求失敗");
}
// 關(guān)閉連接
urlConn.disconnect();
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
Post操作
private void requestPost(HashMap<String, String> paramsMap) {
try {
String baseUrl = "https://baidu.com/";
// 合成參數(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();
// 請求的參數(shù)轉(zhuǎn)換為byte數(shù)組
byte[] postData = params.getBytes();
// 新建一個URL對象
URL url = new URL(baseUrl);
// 打開一個HttpURLConnection連接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 設(shè)置連接超時時間
urlConn.setConnectTimeout(5 * 1000);
// 設(shè)置從主機(jī)讀取數(shù)據(jù)超時
urlConn.setReadTimeout(5 * 1000);
// Post請求必須設(shè)置允許輸出 默認(rèn)false
urlConn.setDoOutput(true);
// 設(shè)置請求允許輸入 默認(rèn)是true
urlConn.setDoInput(true);
// Post請求不能使用緩存
urlConn.setUseCaches(false);
// 設(shè)置為Post請求
urlConn.setRequestMethod("POST");
// 設(shè)置本次連接是否自動處理重定向
urlConn.setInstanceFollowRedirects(true);
// 配置請求Content-Type
urlConn.setRequestProperty("Content-Type", "application/json");
// 開始連接
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());
Log.e(TAG, "Post方式請求成功,result--->" + result);
} else {
Log.e(TAG, "Post方式請求失敗");
}
// 關(guān)閉連接
urlConn.disconnect();
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
download操作
private void downloadFile(String fileUrl){
try {
// 新建一個URL對象
URL url = new URL(fileUrl);
// 打開一個HttpURLConnection連接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 設(shè)置連接主機(jī)超時時間
urlConn.setConnectTimeout(5 * 1000);
// 設(shè)置從主機(jī)讀取數(shù)據(jù)超時
urlConn.setReadTimeout(5 * 1000);
// 設(shè)置是否使用緩存 默認(rèn)是true
urlConn.setUseCaches(true);
// 設(shè)置為Post請求
urlConn.setRequestMethod("GET");
// urlConn設(shè)置請求頭信息
// 設(shè)置請求中的媒體類型信息撮奏。
urlConn.setRequestProperty("Content-Type", "application/json");
// 設(shè)置客戶端與服務(wù)連接類型
urlConn.addRequestProperty("Connection", "Keep-Alive");
// 開始連接
urlConn.connect();
// 判斷請求是否成功
if (urlConn.getResponseCode() == 200) {
String filePath="";
File descFile = new File(filePath);
FileOutputStream fos = new FileOutputStream(descFile);;
byte[] buffer = new byte[1024];
int len;
InputStream inputStream = urlConn.getInputStream();
while ((len = inputStream.read(buffer)) != -1) {
// 寫到本地
fos.write(buffer, 0, len);
}
} else {
Log.e(TAG, "文件下載失敗");
}
// 關(guān)閉連接
urlConn.disconnect();
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
上傳操作
private void upLoadFile(String filePath, HashMap<String, String> paramsMap) {
try {
String baseUrl = "https://baidu.com/uploadFile";
File file = new File(filePath);
// 新建url對象
URL url = new URL(baseUrl);
// 通過HttpURLConnection對象,向網(wǎng)絡(luò)地址發(fā)送請求
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 設(shè)置該連接允許讀取
urlConn.setDoOutput(true);
// 設(shè)置該連接允許寫入
urlConn.setDoInput(true);
// 設(shè)置不能適用緩存
urlConn.setUseCaches(false);
// 設(shè)置連接超時時間
urlConn.setConnectTimeout(5 * 1000); // 設(shè)置連接超時時間
// 設(shè)置讀取超時時間
urlConn.setReadTimeout(5 * 1000); // 讀取超時
// 設(shè)置連接方法post
urlConn.setRequestMethod("POST");
// 設(shè)置維持長連接
urlConn.setRequestProperty("connection", "Keep-Alive");
// 設(shè)置文件字符集
urlConn.setRequestProperty("Accept-Charset", "UTF-8");
// 設(shè)置文件類型
urlConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + "*****");
String name = file.getName();
DataOutputStream requestStream = new DataOutputStream(urlConn.getOutputStream());
requestStream.writeBytes("--" + "*****" + "\r\n");
// 發(fā)送文件參數(shù)信息
StringBuilder tempParams = new StringBuilder();
tempParams.append("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + name + "\"; ");
int pos = 0;
int size = paramsMap.size();
for (String key : paramsMap.keySet()) {
tempParams.append( String.format("%s=\"%s\"", key, paramsMap.get(key), "utf-8"));
if (pos < size-1) {
tempParams.append("; ");
}
pos++;
}
tempParams.append("\r\n");
tempParams.append("Content-Type: application/octet-stream\r\n");
tempParams.append("\r\n");
String params = tempParams.toString();
requestStream.writeBytes(params);
//發(fā)送文件數(shù)據(jù)
FileInputStream fileInput = new FileInputStream(file);
int bytesRead;
byte[] buffer = new byte[1024];
DataInputStream in = new DataInputStream(new FileInputStream(file));
while ((bytesRead = in.read(buffer)) != -1) {
requestStream.write(buffer, 0, bytesRead);
}
requestStream.writeBytes("\r\n");
requestStream.flush();
requestStream.writeBytes("--" + "*****" + "--" + "\r\n");
requestStream.flush();
fileInput.close();
int statusCode = urlConn.getResponseCode();
if (statusCode == 200) {
// 獲取返回的數(shù)據(jù)
String result = streamToString(urlConn.getInputStream());
Log.e(TAG, "上傳成功俏讹,result--->" + result);
} else {
Log.e(TAG, "上傳失敗");
}
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
Request部分
Header | 解釋 | 示例 |
---|---|---|
Accept | 指定客戶端能夠接收的內(nèi)容類型 | Accept: text/plain, text/html |
Accept-Charset | 瀏覽器可以接受的字符編碼集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定瀏覽器可以支持的web服務(wù)器返回內(nèi)容壓縮編碼類型畜吊。 | Accept-Encoding: compress, gzip |
Accept-Language | 瀏覽器可接受的語言 | Accept-Language: en,zh |
Accept-Ranges | 可以請求網(wǎng)頁實(shí)體的一個或者多個子范圍字段 | Accept-Ranges: bytes |
Authorization | HTTP授權(quán)的授權(quán)證書 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定請求和響應(yīng)遵循的緩存機(jī)制 | Cache-Control: no-cache |
Connection | 表示是否需要持久連接泽疆。(HTTP 1.1默認(rèn)進(jìn)行持久連接) | Connection: close |
Cookie | HTTP請求發(fā)送時,會把保存在該請求域名下的所有cookie值一起發(fā)送給web服務(wù)器玲献。 | Cookie: $Version=1; Skin=new; |
Content-Length | 請求的內(nèi)容長度 | Content-Length: 348 |
Content-Type | 請求的與實(shí)體對應(yīng)的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 請求發(fā)送的日期和時間 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 請求的特定的服務(wù)器行為 | Expect: 100-continue |
From | 發(fā)出請求的用戶的Email | From: user@email.com |
Host | 指定請求的服務(wù)器的域名和端口號 | Host: www.zcmhi.com |
If-Match | 只有請求內(nèi)容與實(shí)體相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果請求的部分在指定時間之后被修改則請求成功殉疼,未被修改則返回304代碼 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果內(nèi)容未改變返回304代碼,參數(shù)為服務(wù)器先前發(fā)送的Etag捌年,與服務(wù)器回應(yīng)的Etag比較判斷是否改變 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果實(shí)體未改變瓢娜,服務(wù)器發(fā)送客戶端丟失的部分,否則發(fā)送整個實(shí)體礼预。參數(shù)也為Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在實(shí)體在指定時間之后未被修改才請求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通過代理和網(wǎng)關(guān)傳送的時間 | Max-Forwards: 10 |
Pragma | 用來包含實(shí)現(xiàn)特定的指令 | Pragma: no-cache |
Proxy-Authorization | 連接到代理的授權(quán)證書 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只請求實(shí)體的一部分恋腕,指定范圍 | Range: bytes=500-999 |
Referer | 先前網(wǎng)頁的地址,當(dāng)前請求網(wǎng)頁緊隨其后,即來路 | Referer: http://www.zcmhi.com/archives/71.html |
TE | 客戶端愿意接受的傳輸編碼逆瑞,并通知服務(wù)器接受接受尾加頭信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服務(wù)器指定某種傳輸協(xié)議以便服務(wù)器進(jìn)行轉(zhuǎn)換(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的內(nèi)容包含發(fā)出請求的用戶信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中間網(wǎng)關(guān)或代理服務(wù)器地址荠藤,通信協(xié)議 | Via: 1.0 fred, 1.1 nowhere.com |
Responses 部分
Header | 解釋 | 示例 |
---|---|---|
Accept-Ranges | 表明服務(wù)器是否支持指定范圍請求及哪種類型的分段請求 | Accept-Ranges: bytes |
Age | 從原始服務(wù)器到代理緩存形成的估算時間(以秒計伙单,非負(fù)) | Age: 12 |
Allow | 對某網(wǎng)絡(luò)資源的有效的請求行為,不允許則返回405 | Allow: GET, HEAD |
Cache-Control | 告訴所有的緩存機(jī)制是否可以緩存及哪種類型 | Cache-Control: no-cache |
Content-Encoding | web服務(wù)器支持的返回內(nèi)容壓縮編碼類型哈肖。 | Content-Encoding: gzip |
Content-Language | 響應(yīng)體的語言 | Content-Language: en,zh |
Content-Length | 響應(yīng)體的長度 | Content-Length: 348 |
Content-Location | 請求資源可替代的備用的另一地址 | Content-Location: /index.htm |
Content-MD5 | 返回資源的MD5校驗(yàn)值 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
Content-Range | 在整個返回體中本部分的字節(jié)位置 | Content-Range: bytes 21010-47021/47022 |
Content-Type | 返回內(nèi)容的MIME類型 | Content-Type: text/html; charset=utf-8 |
Date | 原始服務(wù)器消息發(fā)出的時間 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
ETag | 請求變量的實(shí)體標(biāo)簽的當(dāng)前值 | ETag: “737060cd8c284d8af7ad3082f209582d” |
Expires | 響應(yīng)過期的日期和時間 | Expires: Thu, 01 Dec 2010 16:00:00 GMT |
Last-Modified | 請求資源的最后修改時間 | Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT |
Location | 用來重定向接收方到非請求URL的位置來完成請求或標(biāo)識新的資源 | Location: http://www.zcmhi.com/archives/94.html |
Pragma | 包括實(shí)現(xiàn)特定的指令吻育,它可應(yīng)用到響應(yīng)鏈上的任何接收方 | Pragma: no-cache |
Proxy-Authenticate | 它指出認(rèn)證方案和可應(yīng)用到代理的該URL上的參數(shù) | Proxy-Authenticate: Basic |
refresh | 應(yīng)用于重定向或一個新的資源被創(chuàng)造淤井,在5秒之后重定向(由網(wǎng)景提出布疼,被大部分瀏覽器支持) | Refresh: 5; url=http://www.zcmhi.com/archives/94.html |
Retry-After | 如果實(shí)體暫時不可取,通知客戶端在指定時間之后再次嘗試 | Retry-After: 120 |
Server | web服務(wù)器軟件名稱 | Server: Apache/1.3.27 (Unix) (Red-Hat/Linux) |
Set-Cookie | 設(shè)置Http Cookie | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
Trailer | 指出頭域在分塊傳輸編碼的尾部存在 | Trailer: Max-Forwards |
Transfer-Encoding | 文件傳輸編碼 | Transfer-Encoding:chunked |
Vary | 告訴下游代理是使用緩存響應(yīng)還是從原始服務(wù)器請求 | Vary: * |
Via | 告知代理客戶端響應(yīng)是通過哪里發(fā)送的 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 警告實(shí)體可能存在的問題 | Warning: 199 Miscellaneous warning |
WWW-Authenticate | 表明客戶端請求實(shí)體應(yīng)該使用的授權(quán)方案 | WWW-Authenticate: Basic |
注意點(diǎn)
- HttpURLConnection的connect()函數(shù)币狠,實(shí)際上只是建立了一個與服務(wù)器的tcp連接游两,并沒有實(shí)際發(fā)送http請求。 無論是post還是get漩绵,http請求實(shí)際上直到HttpURLConnection的getInputStream()這個函數(shù)里面才正式發(fā)送出去贱案。
- 在用POST方式發(fā)送URL請求時,URL請求參數(shù)的設(shè)定順序是重中之重止吐,對connection對象的一切配置(那一堆set函數(shù)) 都必須要在connect()函數(shù)執(zhí)行之前完成宝踪。而對outputStream的寫操作,又必須要在inputStream的讀操作之前碍扔。這些順序?qū)嶋H上是由http請求的格式?jīng)Q定的瘩燥。
- http請求實(shí)際上由兩部分組成,一個是http頭不同,所有關(guān)于此次http請求的配置都在http頭里面定義厉膀, 一個是正文content。connect()函數(shù)會根據(jù)HttpURLConnection對象的配置值生成http頭部信息二拐,因此在調(diào)用connect函數(shù)之前站蝠,就必須把所有的配置準(zhǔn)備好。
- 在http頭后面緊跟著的是http請求的正文卓鹿,正文的內(nèi)容是通過outputStream流寫入的菱魔,實(shí)際上outputStream不是一個網(wǎng)絡(luò)流,充其量是個字符串流吟孙,往里面寫入的東西不會立即發(fā)送到網(wǎng)絡(luò)澜倦, 而是存在于內(nèi)存緩沖區(qū)中,待outputStream流關(guān)閉時杰妓,根據(jù)輸入的內(nèi)容生成http正文藻治。至此,http請求的東西已經(jīng)全部準(zhǔn)備就緒巷挥。在getInputStream()函數(shù)調(diào)用的時候桩卵,就會把準(zhǔn)備好的http請求 正式發(fā)送到服務(wù)器了,然后返回一個輸入流,用于讀取服務(wù)器對于此次http請求的返回信息雏节。由于http 請求在getInputStream的時候已經(jīng)發(fā)送出去了(包括http頭和正文)胜嗓,因此在getInputStream()函數(shù) 之后對connection對象進(jìn)行設(shè)置(對http頭的信息進(jìn)行修改)或者寫入outputStream(對正文進(jìn)行修改)都是沒有意義的了,執(zhí)行這些操作會導(dǎo)致異常的發(fā)生钩乍。