編輯:Android資訊
Android中發送http網絡請求是很常見的,要有GET請求和POST請求。一個完整的http請求需要經歷兩個過程:客戶端發送請求到服務器,然後服務器將結果返回給客戶端,如下圖所示:

響應頭包含了服務器想要告訴客戶端的一些元數據信息,注意不是數據,是元數據,比如通過響應頭Content-Encoding告訴客戶端服務器所采用的壓縮格式,響應頭Content-Type告訴客戶端響應體是什麼格式的數據,再比如服務端可以通過多個Set-Cookie響應頭向客戶端寫入多條Cookie信息,等等。剛剛提到的幾個請求頭都是W3C規定的標准的請求頭名稱,我們也可以在服務端向客戶端寫入自定義的響應頭。
Http協議支持的操作有GET、POST、HEAD、PUT、TRACE、OPTIONS、DELETE,其中最最常用的還是GET和POST操作,下面我們看一下GET和POST的區別。
GET:
POST:
在Android API Level 9(Android 2.2)之前之能使用DefaultHttpClient類發送http請求。DefaultHttpClient是Apache用於發送http請求的客戶端,其提供了強大的API支持,而且基本沒有什麼bug,但是由於其太過復雜,Android團隊在保持向後兼容的情況下,很難對DefaultHttpClient進行增強。為此,Android團隊從Android API Level 9開始自己實現了一個發送http請求的客戶端類——–HttpURLConnection。
相比於DefaultHttpClient,HttpURLConnection比較輕量級,雖然功能沒有DefaultHttpClient那麼強大,但是能夠滿足大部分的需求,所以Android推薦使用HttpURLConnection代替DefaultHttpClient,並不強制使用HttpURLConnection。
但從Android API Level 23(Android 6.0)開始,不能再在Android中使用DefaultHttpClient,強制使用HttpURLConnection。
為了演示HttpURLConnection的常見用法,我做了一個App,界面如下所示:

主界面MainActivity有四個按鈕,分別表示用GET發送請求、用POST發送鍵值對數據、用POST發送XML數據以及用POST發送JSON數據,點擊對應的按鈕會啟動NetworkActivity並執行相應的操作。
NetworkActivity的源碼如下所示,此處先貼出代碼,後面會詳細說明。
package com.ispring.httpurlconnection;
import android.content.Intent;
import android.content.res.AssetManager;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class NetworkActivity extends AppCompatActivity {
private NetworkAsyncTask networkAsyncTask = new NetworkAsyncTask();
private TextView tvUrl = null;
private TextView tvRequestHeader = null;
private TextView tvRequestBody = null;
private TextView tvResponseHeader = null;
private TextView tvResponseBody = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network);
tvUrl = (TextView) findViewById(R.id.tvUrl);
tvRequestHeader = (TextView) findViewById(R.id.tvRequestHeader);
tvRequestBody = (TextView) findViewById(R.id.tvRequestBody);
tvResponseHeader = (TextView) findViewById(R.id.tvResponseHeader);
tvResponseBody = (TextView) findViewById(R.id.tvResponseBody);
Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
String networkAction = intent.getStringExtra("action");
networkAsyncTask.execute(networkAction);
}
}
//用於進行網絡請求的AsyncTask
class NetworkAsyncTask extends AsyncTask<String, Integer, Map<String, Object>> {
//NETWORK_GET表示發送GET請求
public static final String NETWORK_GET = "NETWORK_GET";
//NETWORK_POST_KEY_VALUE表示用POST發送鍵值對數據
public static final String NETWORK_POST_KEY_VALUE = "NETWORK_POST_KEY_VALUE";
//NETWORK_POST_XML表示用POST發送XML數據
public static final String NETWORK_POST_XML = "NETWORK_POST_XML";
//NETWORK_POST_JSON表示用POST發送JSON數據
public static final String NETWORK_POST_JSON = "NETWORK_POST_JSON";
@Override
protected Map<String, Object> doInBackground(String... params) {
Map<String,Object> result = new HashMap<>();
URL url = null;//請求的URL地址
HttpURLConnection conn = null;
String requestHeader = null;//請求頭
byte[] requestBody = null;//請求體
String responseHeader = null;//響應頭
byte[] responseBody = null;//響應體
String action = params[0];//http請求的操作類型
try {
if (NETWORK_GET.equals(action)) {
//發送GET請求
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet?name=孫群&age=27");
conn = (HttpURLConnection) url.openConnection();
//HttpURLConnection默認就是用GET發送請求,所以下面的setRequestMethod可以省略
conn.setRequestMethod("GET");
//HttpURLConnection默認也支持從服務端讀取結果流,所以下面的setDoInput也可以省略
conn.setDoInput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_GET);
//禁用網絡緩存
conn.setUseCaches(false);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//在對各種參數配置完成後,通過調用connect方法建立TCP連接,但是並未真正獲取數據
//conn.connect()方法不必顯式調用,當調用conn.getInputStream()方法時內部也會自動調用connect方法
conn.connect();
//調用getInputStream方法後,服務端才會收到請求,並阻塞式地接收服務端返回的數據
InputStream is = conn.getInputStream();
//將InputStream轉換成byte數組,getBytesByInputStream會關閉輸入流
responseBody = getBytesByInputStream(is);
//獲取響應頭
responseHeader = getResponseHeader(conn);
} else if (NETWORK_POST_KEY_VALUE.equals(action)) {
//用POST發送鍵值對數據
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet");
conn = (HttpURLConnection) url.openConnection();
//通過setRequestMethod將conn設置成POST方法
conn.setRequestMethod("POST");
//調用conn.setDoOutput()方法以顯式開啟請求體
conn.setDoOutput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_POST_KEY_VALUE);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//獲取conn的輸出流
OutputStream os = conn.getOutputStream();
//獲取兩個鍵值對name=孫群和age=27的字節數組,將該字節數組作為請求體
requestBody = new String("name=孫群&age=27").getBytes("UTF-8");
//將請求體寫入到conn的輸出流中
os.write(requestBody);
//記得調用輸出流的flush方法
os.flush();
//關閉輸出流
os.close();
//當調用getInputStream方法時才真正將請求體數據上傳至服務器
InputStream is = conn.getInputStream();
//獲得響應體的字節數組
responseBody = getBytesByInputStream(is);
//獲得響應頭
responseHeader = getResponseHeader(conn);
} else if (NETWORK_POST_XML.equals(action)) {
//用POST發送XML數據
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet");
conn = (HttpURLConnection) url.openConnection();
//通過setRequestMethod將conn設置成POST方法
conn.setRequestMethod("POST");
//調用conn.setDoOutput()方法以顯式開啟請求體
conn.setDoOutput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_POST_XML);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//獲取conn的輸出流
OutputStream os = conn.getOutputStream();
//讀取assets目錄下的person.xml文件,將其字節數組作為請求體
requestBody = getBytesFromAssets("person.xml");
//將請求體寫入到conn的輸出流中
os.write(requestBody);
//記得調用輸出流的flush方法
os.flush();
//關閉輸出流
os.close();
//當調用getInputStream方法時才真正將請求體數據上傳至服務器
InputStream is = conn.getInputStream();
//獲得響應體的字節數組
responseBody = getBytesByInputStream(is);
//獲得響應頭
responseHeader = getResponseHeader(conn);
} else if (NETWORK_POST_JSON.equals(action)) {
//用POST發送JSON數據
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet");
conn = (HttpURLConnection) url.openConnection();
//通過setRequestMethod將conn設置成POST方法
conn.setRequestMethod("POST");
//調用conn.setDoOutput()方法以顯式開啟請求體
conn.setDoOutput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_POST_JSON);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//獲取conn的輸出流
OutputStream os = conn.getOutputStream();
//讀取assets目錄下的person.json文件,將其字節數組作為請求體
requestBody = getBytesFromAssets("person.json");
//將請求體寫入到conn的輸出流中
os.write(requestBody);
//記得調用輸出流的flush方法
os.flush();
//關閉輸出流
os.close();
//當調用getInputStream方法時才真正將請求體數據上傳至服務器
InputStream is = conn.getInputStream();
//獲得響應體的字節數組
responseBody = getBytesByInputStream(is);
//獲得響應頭
responseHeader = getResponseHeader(conn);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//最後將conn斷開連接
if (conn != null) {
conn.disconnect();
}
}
result.put("url", url.toString());
result.put("action", action);
result.put("requestHeader", requestHeader);
result.put("requestBody", requestBody);
result.put("responseHeader", responseHeader);
result.put("responseBody", responseBody);
return result;
}
@Override
protected void onPostExecute(Map<String, Object> result) {
super.onPostExecute(result);
String url = (String)result.get("url");//請求的URL地址
String action = (String) result.get("action");//http請求的操作類型
String requestHeader = (String) result.get("requestHeader");//請求頭
byte[] requestBody = (byte[]) result.get("requestBody");//請求體
String responseHeader = (String) result.get("responseHeader");//響應頭
byte[] responseBody = (byte[]) result.get("responseBody");//響應體
//更新tvUrl,顯示Url
tvUrl.setText(url);
//更新tvRequestHeader,顯示請求頭
if (requestHeader != null) {
tvRequestHeader.setText(requestHeader);
}
//更新tvRequestBody,顯示請求體
if(requestBody != null){
try{
String request = new String(requestBody, "UTF-8");
tvRequestBody.setText(request);
}catch (UnsupportedEncodingException e){
e.printStackTrace();
}
}
//更新tvResponseHeader,顯示響應頭
if (responseHeader != null) {
tvResponseHeader.setText(responseHeader);
}
//更新tvResponseBody,顯示響應體
if (NETWORK_GET.equals(action)) {
String response = getStringByBytes(responseBody);
tvResponseBody.setText(response);
} else if (NETWORK_POST_KEY_VALUE.equals(action)) {
String response = getStringByBytes(responseBody);
tvResponseBody.setText(response);
} else if (NETWORK_POST_XML.equals(action)) {
//將表示xml的字節數組進行解析
String response = parseXmlResultByBytes(responseBody);
tvResponseBody.setText(response);
} else if (NETWORK_POST_JSON.equals(action)) {
//將表示json的字節數組進行解析
String response = parseJsonResultByBytes(responseBody);
tvResponseBody.setText(response);
}
}
//讀取請求頭
private String getReqeustHeader(HttpURLConnection conn) {
//https://github.com/square/okhttp/blob/master/okhttp-urlconnection/src/main/java/okhttp3/internal/huc/HttpURLConnectionImpl.java#L236
Map<String, List<String>> requestHeaderMap = conn.getRequestProperties();
Iterator<String> requestHeaderIterator = requestHeaderMap.keySet().iterator();
StringBuilder sbRequestHeader = new StringBuilder();
while (requestHeaderIterator.hasNext()) {
String requestHeaderKey = requestHeaderIterator.next();
String requestHeaderValue = conn.getRequestProperty(requestHeaderKey);
sbRequestHeader.append(requestHeaderKey);
sbRequestHeader.append(":");
sbRequestHeader.append(requestHeaderValue);
sbRequestHeader.append("\n");
}
return sbRequestHeader.toString();
}
//讀取響應頭
private String getResponseHeader(HttpURLConnection conn) {
Map<String, List<String>> responseHeaderMap = conn.getHeaderFields();
int size = responseHeaderMap.size();
StringBuilder sbResponseHeader = new StringBuilder();
for(int i = 0; i < size; i++){
String responseHeaderKey = conn.getHeaderFieldKey(i);
String responseHeaderValue = conn.getHeaderField(i);
sbResponseHeader.append(responseHeaderKey);
sbResponseHeader.append(":");
sbResponseHeader.append(responseHeaderValue);
sbResponseHeader.append("\n");
}
return sbResponseHeader.toString();
}
//根據字節數組構建UTF-8字符串
private String getStringByBytes(byte[] bytes) {
String str = "";
try {
str = new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return str;
}
//從InputStream中讀取數據,轉換成byte數組,最後關閉InputStream
private byte[] getBytesByInputStream(InputStream is) {
byte[] bytes = null;
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(baos);
byte[] buffer = new byte[1024 * 8];
int length = 0;
try {
while ((length = bis.read(buffer)) > 0) {
bos.write(buffer, 0, length);
}
bos.flush();
bytes = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bytes;
}
//根據文件名,從asserts目錄中讀取文件的字節數組
private byte[] getBytesFromAssets(String fileName){
byte[] bytes = null;
AssetManager assetManager = getAssets();
InputStream is = null;
try{
is = assetManager.open(fileName);
bytes = getBytesByInputStream(is);
}catch (IOException e){
e.printStackTrace();
}
return bytes;
}
//將表示xml的字節數組進行解析
private String parseXmlResultByBytes(byte[] bytes) {
InputStream is = new ByteArrayInputStream(bytes);
StringBuilder sb = new StringBuilder();
List<Person> persons = XmlParser.parse(is);
for (Person person : persons) {
sb.append(person.toString()).append("\n");
}
return sb.toString();
}
//將表示json的字節數組進行解析
private String parseJsonResultByBytes(byte[] bytes){
String jsonString = getStringByBytes(bytes);
List<Person> persons = JsonParser.parse(jsonString);
StringBuilder sb = new StringBuilder();
for (Person person : persons) {
sb.append(person.toString()).append("\n");
}
return sb.toString();
}
}
}
這個App是用來發送http請求的客戶端,除此之外,我還創建了一個JSP的WebProject作為服務端,用Servlet對客戶端發來的請求進行處理,Servlet的代碼如下所示:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Enumeration;
@WebServlet(name = "MyServlet")
public class MyServlet extends HttpServlet {
//GET請求
private static final String NETWORK_GET = "NETWORK_GET";
//用POST發送鍵值對
private static final String NETWORK_POST_KEY_VALUE = "NETWORK_POST_KEY_VALUE";
//用POST發送XML數據
private static final String NETWORK_POST_XML = "NETWORK_POST_XML";
//用POST發送JSON數據
private static final String NETWORK_POST_JSON = "NETWORK_POST_JSON";
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getHeader("action");
//將輸入與輸出都設置為UTF-8編碼
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/plain;charset=UTF-8");
//response.setHeader("content-type","text/plain;charset=UTF-8");
if(NETWORK_GET.equals(action) || NETWORK_POST_KEY_VALUE.equals(action)){
//對於NETWORK_GET和NETWORK_POST_KEY_VALUE,遍歷鍵值對,並將鍵值對重新寫回到輸出結果中
Enumeration<String> parameterNames = request.getParameterNames();
PrintWriter writer = response.getWriter();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
String value = request.getParameter(name);
if(request.getMethod().toUpperCase().equals("GET")){
//GET請求需要進行編碼轉換,POST不需要
value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
}
writer.write(name + "=" + value + "\n");
}
writer.flush();
writer.close();
}else if(NETWORK_POST_XML.equals(action) || NETWORK_POST_JSON.equals(action)){
//對於NETWORK_POST_XML和NETWORK_POST_JSON,將請求體重新寫入到響應體的輸出流中
//通過request.getInputStream()得到http請求的請求體
BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
//通過response.getOutputStream()得到http請求的響應體
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[1024 * 8];
int length = 0;
while ( (length = bis.read(buffer)) > 0){
bos.write(buffer, 0, length);
}
bos.flush();
bos.close();
bis.close();
}else{
PrintWriter writer = response.getWriter();
writer.write("非法的請求頭: action");
writer.flush();
writer.close();
}
}
}
由於網絡請求耗時而且會阻塞當前線程,所以我們將發送http請求的操作都放到NetworkAsyncTask中,NetworkAsyncTask是繼承自AsyncTask。
點擊”GET”按鈕後,界面如下所示:

GET請求是最簡單的http請求,其發送請求的代碼如下所示:
if (NETWORK_GET.equals(action)) {
//發送GET請求
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet?name=孫群&age=27");
conn = (HttpURLConnection) url.openConnection();
//HttpURLConnection默認就是用GET發送請求,所以下面的setRequestMethod可以省略
conn.setRequestMethod("GET");
//HttpURLConnection默認也支持從服務端讀取結果流,所以下面的setDoInput也可以省略
conn.setDoInput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_GET);
//禁用網絡緩存
conn.setUseCaches(false);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//在對各種參數配置完成後,通過調用connect方法建立TCP連接,但是並未真正獲取數據
//conn.connect()方法不必顯式調用,當調用conn.getInputStream()方法時內部也會自動調用connect方法
conn.connect();
//調用getInputStream方法後,服務端才會收到請求,並阻塞式地接收服務端返回的數據
InputStream is = conn.getInputStream();
//將InputStream轉換成byte數組,getBytesByInputStream會關閉輸入流
responseBody = getBytesByInputStream(is);
//獲取響應頭
responseHeader = getResponseHeader(conn);
}
上面的注釋寫的比較詳細了,此處對代碼進行一下簡單說明。
?name=孫群&age=27,這樣就相當於添加了兩個鍵值對,其形式如?key1=value1&key2=value2&key3=value3,在?後面添加鍵值對,鍵和值之間用=相連,鍵值對之間用&分隔,服務端可以讀取這些鍵值對信息。 //讀取請求頭
private String getReqeustHeader(HttpURLConnection conn) {
Map<String, List<String>> requestHeaderMap = conn.getRequestProperties();
Iterator<String> requestHeaderIterator = requestHeaderMap.keySet().iterator();
StringBuilder sbRequestHeader = new StringBuilder();
while (requestHeaderIterator.hasNext()) {
String requestHeaderKey = requestHeaderIterator.next();
String requestHeaderValue = conn.getRequestProperty(requestHeaderKey);
sbRequestHeader.append(requestHeaderKey);
sbRequestHeader.append(":");
sbRequestHeader.append(requestHeaderValue);
sbRequestHeader.append("\n");
}
return sbRequestHeader.toString();
}
我們還可以通過getResponseHeader方法獲取響應頭,代碼如下所示:
//讀取響應頭
private String getResponseHeader(HttpURLConnection conn) {
Map<String, List<String>> responseHeaderMap = conn.getHeaderFields();
int size = responseHeaderMap.size();
StringBuilder sbResponseHeader = new StringBuilder();
for(int i = 0; i < size; i++){
String responseHeaderKey = conn.getHeaderFieldKey(i);
String responseHeaderValue = conn.getHeaderField(i);
sbResponseHeader.append(responseHeaderKey);
sbResponseHeader.append(":");
sbResponseHeader.append(responseHeaderValue);
sbResponseHeader.append("\n");
}
return sbResponseHeader.toString();
}
通過方法getHeaderFieldKey可以獲得響應頭的key值,通過方法getHeaderField可以獲得響應頭的value值。
在後台的Servelt中將鍵值對信息重新原樣寫入到客戶端,服務端的代碼如下所示:
if(NETWORK_GET.equals(action) || NETWORK_POST_KEY_VALUE.equals(action)){
//對於NETWORK_GET和NETWORK_POST_KEY_VALUE,遍歷鍵值對,並將鍵值對重新寫回到輸出結果中
Enumeration<String> parameterNames = request.getParameterNames();
PrintWriter writer = response.getWriter();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
String value = request.getParameter(name);
if(request.getMethod().toUpperCase().equals("GET")){
//GET請求需要進行編碼轉換,POST不需要
value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
}
writer.write(name + "=" + value + "\n");
}
writer.flush();
writer.close();
}
在接收到服務端返回的數據後,在AsyncTask的onPostExecute方法中會將Url、請求頭、響應頭、響應體的值展示在UI上。
點擊”POST KEY VALUE”按鈕,可以用POST發送鍵值對數據,界面如下所示:

代碼如下所示:
if (NETWORK_POST_KEY_VALUE.equals(action)) {
//用POST發送鍵值對數據
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet");
conn = (HttpURLConnection) url.openConnection();
//通過setRequestMethod將conn設置成POST方法
conn.setRequestMethod("POST");
//調用conn.setDoOutput()方法以顯式開啟請求體
conn.setDoOutput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_POST_KEY_VALUE);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//獲取conn的輸出流
OutputStream os = conn.getOutputStream();
//獲取兩個鍵值對name=孫群和age=27的字節數組,將該字節數組作為請求體
requestBody = new String("name=孫群&age=27").getBytes("UTF-8");
//將請求體寫入到conn的輸出流中
os.write(requestBody);
//記得調用輸出流的flush方法
os.flush();
//關閉輸出流
os.close();
//當調用getInputStream方法時才真正將請求體數據上傳至服務器
InputStream is = conn.getInputStream();
//獲得響應體的字節數組
responseBody = getBytesByInputStream(is);
//獲得響應頭
responseHeader = getResponseHeader(conn);
}
使用POST發送請求的代碼與用GET發送請求的代碼大部分類似,我們只對其中不同的地方做下說明。
在我們的服務器端的Servlet中,在接收到POST請求發送的鍵值對數據後,也只是簡單地將鍵值對數據原樣寫入給客戶端,具體代碼參見上文,不再贅述。
點擊”POST XML”按鈕,可以用POST發送XML數據,界面如下所示:

代碼如下所示:
if (NETWORK_POST_XML.equals(action)) {
//用POST發送XML數據
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet");
conn = (HttpURLConnection) url.openConnection();
//通過setRequestMethod將conn設置成POST方法
conn.setRequestMethod("POST");
//調用conn.setDoOutput()方法以顯式開啟請求體
conn.setDoOutput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_POST_XML);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//獲取conn的輸出流
OutputStream os = conn.getOutputStream();
//讀取assets目錄下的person.xml文件,將其字節數組作為請求體
requestBody = getBytesFromAssets("person.xml");
//將請求體寫入到conn的輸出流中
os.write(requestBody);
//記得調用輸出流的flush方法
os.flush();
//關閉輸出流
os.close();
//當調用getInputStream方法時才真正將請求體數據上傳至服務器
InputStream is = conn.getInputStream();
//獲得響應體的字節數組
responseBody = getBytesByInputStream(is);
//獲得響應頭
responseHeader = getResponseHeader(conn);
}
上面的代碼與用POST發送鍵值對的代碼很相似,對其進行簡單說明。
<?xml version="1.0" encoding="utf-8"?>
<persons>
<person id="101">
<name>張三</name>
<age>27</age>
</person>
<person id="102">
<name>李四</name>
<age>28</age>
</person>
</persons>
<person>標簽對應著Person類,Person類代碼如下所示:
package com.ispring.httpurlconnection;
public class Person {
private String id = "";
private String name = "";
private int age = 0;
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return new StringBuilder().append("name:").append(getName()).append(", age:").append(getAge()).toString();
}
}
服務端接收到客戶端發送來的XML數據之後,只是簡單的將其原樣寫回到客戶端,即客戶端接收到的響應體還是原來的XML數據,然後客戶端通過parseXmlResultByBytes方法對該XML數據進行解析,將字節數組轉換成List<Person>,parseXmlResultByBytes代碼如下所示:
//將表示xml的字節數組進行解析
private String parseXmlResultByBytes(byte[] bytes) {
InputStream is = new ByteArrayInputStream(bytes);
StringBuilder sb = new StringBuilder();
List<Person> persons = XmlParser.parse(is);
for (Person person : persons) {
sb.append(person.toString()).append("\n");
}
return sb.toString();
}
該方法使用了自定義的XmlParser類對XML數據進行解析,其源碼如下所示:
package com.ispring.httpurlconnection;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class XmlParser {
public static List<Person> parse(InputStream is) {
List<Person> persons = new ArrayList<>();
try{
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
PersonHandler personHandler = new PersonHandler();
parser.parse(is, personHandler);
persons = personHandler.getPersons();
}catch (Exception e){
e.printStackTrace();
}
return persons;
}
static class PersonHandler extends DefaultHandler {
private List<Person> persons;
private Person temp;
private StringBuilder sb;
public List<Person> getPersons(){
return persons;
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
persons = new ArrayList<>();
sb = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
sb.setLength(0);
if(localName.equals("person")){
temp = new Person();
int length = attributes.getLength();
for(int i = 0; i < length; i++){
String name = attributes.getLocalName(i);
if(name.equals("id")){
String value = attributes.getValue(i);
temp.setId(value);
}
}
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
sb.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if(localName.equals("name")){
String name = sb.toString();
temp.setName(name);
}else if(localName.equals("age")){
int age = Integer.parseInt(sb.toString());
temp.setAge(age);
}else if(localName.equals("person")){
persons.add(temp);
}
}
}
}
點擊”POST JSON”按鈕,可以用POST發送JSON數據,界面如下所示:

代碼如下所示:
if (NETWORK_POST_JSON.equals(action)) {
//用POST發送JSON數據
url = new URL("http://192.168.31.200:8080/HttpServer/MyServlet");
conn = (HttpURLConnection) url.openConnection();
//通過setRequestMethod將conn設置成POST方法
conn.setRequestMethod("POST");
//調用conn.setDoOutput()方法以顯式開啟請求體
conn.setDoOutput(true);
//用setRequestProperty方法設置一個自定義的請求頭:action,由於後端判斷
conn.setRequestProperty("action", NETWORK_POST_JSON);
//獲取請求頭
requestHeader = getReqeustHeader(conn);
//獲取conn的輸出流
OutputStream os = conn.getOutputStream();
//讀取assets目錄下的person.json文件,將其字節數組作為請求體
requestBody = getBytesFromAssets("person.json");
//將請求體寫入到conn的輸出流中
os.write(requestBody);
//記得調用輸出流的flush方法
os.flush();
//關閉輸出流
os.close();
//當調用getInputStream方法時才真正將請求體數據上傳至服務器
InputStream is = conn.getInputStream();
//獲得響應體的字節數組
responseBody = getBytesByInputStream(is);
//獲得響應頭
responseHeader = getResponseHeader(conn);
}
上面的代碼與用POST發送XML的代碼很相似,對其進行簡單說明。
{
"persons": [{
"id": "101",
"name":"張三",
"age":27
}, {
"id": "102",
"name":"李四",
"age":28
}]
}
Person對象。 //將表示json的字節數組進行解析
private String parseJsonResultByBytes(byte[] bytes){
String jsonString = getStringByBytes(bytes);
List<Person> persons = JsonParser.parse(jsonString);
StringBuilder sb = new StringBuilder();
for (Person person : persons) {
sb.append(person.toString()).append("\n");
}
return sb.toString();
}
該方法又使用了自定義的JsonParset類,源碼如下所示:
package com.ispring.httpurlconnection;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class JsonParser {
public static List<Person> parse(String jsonString){
List<Person> persons = new ArrayList<>();
try{
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray("persons");
int length = jsonArray.length();
for(int i = 0; i < length; i++){
JSONObject personObject = jsonArray.getJSONObject(i);
String id = personObject.getString("id");
String name = personObject.getString("name");
int age = personObject.getInt("age");
Person person = new Person();
person.setId(id);
person.setName(name);
person.setAge(age);
persons.add(person);
}
}catch (JSONException e){
e.printStackTrace();
}
return persons;
}
}
希望本文對大家使用HttpURLConnection有所幫助!
Android UI 自動化測試實現過程
介紹 Android測試支持庫包含 UI自動化模塊 ,它可以對Android應用進行自動黑盒測試。在API Level 18中引入了自動化模塊,它允許開發者在組成
Android Dialog的7種形式實現方式
在Android開發中,我們經常會需要在Android界面上彈出一些對話框,比如詢問用戶或者讓用戶選擇。這些功能我們叫它Android Dialog對話框,在我們
每個Android開發者應該知道的6個SDK和API
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! 說到軟件開發,有人或許會感歎了解平台SDK和API比了解語言本身更
Android開發者需要面對的8大挑戰
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! 移動開發變得越來越受歡迎,但移動開發者正面臨著一系列挑戰。本文將介