編輯:Android資訊
Android中發送http網絡請求是很常見的,要有GET請求和POST請求。一個完整的http請求需要經歷兩個過程:客戶端發送請求到服務器,然後服務器將結果返回給客戶端,如下圖所示:
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應用進行自動黑盒測試。在API Level 18中引入了自動化模塊,它允許開發者在組成
在Android開發中,我們經常會需要在Android界面上彈出一些對話框,比如詢問用戶或者讓用戶選擇。這些功能我們叫它Android Dialog對話框,在我們
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! 說到軟件開發,有人或許會感歎了解平台SDK和API比了解語言本身更
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! 移動開發變得越來越受歡迎,但移動開發者正面臨著一系列挑戰。本文將介