[安卓] 1四、安卓HTTP——POST和GET用法分析

 

內容簡介html

本文經過創建一個簡單的Servlet服務器來分析安卓上用HTTP和服務器通訊的細節,旨在演示C/S模式下服務器端和客戶端的工做過程。java

目錄android

part.1 用MyEclipse創建一個簡單的servlet服務器git

part.2 安卓HTTP的POST和GET請求方法github

part.3 本例中C/S雙方工做機制分析web

part.4 拓展知識瀏覽器


 

注:這裏首先假設您已經正確安裝好了MyEclipse及Tomcat並作了相應的配置,能夠支持開發並部署一個簡單的Java Web工程;假設您已經安裝了Eclipse並配置好Android相應開發環境。緩存

part.1 用MyEclipse創建一個簡單的servlet服務器安全

在MyEclipse中File->New->Other->Web Project->Next->Project Name取beautifulzzzz(隨便)->Finish,從而新建一個Java Web Project。服務器

在web.xml中<welcome-file-list>標籤對中指明瞭打開網站的首頁爲index.jsp,接着點擊1號按鈕選擇一個服務器,而後點擊2號按鈕將web工程部署到該服務器上,而後在瀏覽器中輸入http://localhost:8080/beautifulzzzz/就能看到相應的頁面:

如今在src中新建一個名爲hello的servlet,並添加相應函數(最終以下):

  1 import java.io.IOException;
  2 import java.io.PrintWriter;
  3 import java.util.Map;
  4 
  5 import javax.servlet.ServletException;
  6 import javax.servlet.http.HttpServlet;
  7 import javax.servlet.http.HttpServletRequest;
  8 import javax.servlet.http.HttpServletResponse;
  9 
 10 public class hello extends HttpServlet {
 11 
 12     /**
 13      * Constructor of the object.
 14      */
 15     public hello() {
 16         super();
 17     }
 18 
 19     /**
 20      * Destruction of the servlet. <br>
 21      */
 22     public void destroy() {
 23         super.destroy(); // Just puts "destroy" string in log
 24         // Put your code here
 25     }
 26 
 27     /**
 28      * The doGet method of the servlet. <br>
 29      * 
 30      * This method is called when a form has its tag value method equals to get.
 31      * 
 32      * @param request
 33      *            the request send by the client to the server
 34      * @param response
 35      *            the response send by the server to the client
 36      * @throws ServletException
 37      *             if an error occurred
 38      * @throws IOException
 39      *             if an error occurred
 40      */
 41     /*
 42      * 以Get方式訪問頁面時執行該函數 執行doGet前會先執行getLastModified,若是瀏覽器發現getLastModified返回數值
 43      * 與上次訪問返回數值相同,則認爲該文檔沒有更新,瀏覽器執行緩存而不執行doGet 若是返回-1則認爲是實時更新的,老是執行該函數
 44      */
 45     public void doGet(HttpServletRequest request, HttpServletResponse response)
 46             throws ServletException, IOException {
 47         this.log("執行 doGet 方法...");
 48         this.execute(request, response);
 49     }
 50 
 51     /**
 52      * The doPost method of the servlet. <br>
 53      * 
 54      * This method is called when a form has its tag value method equals to
 55      * post.
 56      * 
 57      * @param request
 58      *            the request send by the client to the server
 59      * @param response
 60      *            the response send by the server to the client
 61      * @throws ServletException
 62      *             if an error occurred
 63      * @throws IOException
 64      *             if an error occurred 執行前不會執行getLastModified
 65      */
 66     public void doPost(HttpServletRequest request, HttpServletResponse response)
 67             throws ServletException, IOException {
 68         this.log("執行 doPost 方法...");
 69         this.execute(request, response);
 70     }
 71 
 72     /**
 73      * 返回該Servlet生成文檔的更新時間。對Get方法有效 返回的時間爲相對於1970年1月1日08:00:00的毫秒數
 74      * 若是返回-1表示實時更新。默認爲-1
 75      */
 76     @Override
 77     public long getLastModified(HttpServletRequest request) {
 78         this.log("執行 getLastModified 方法...");
 79         return -1;
 80     }
 81 
 82     // 執行方法
 83     private void execute(HttpServletRequest request,
 84             HttpServletResponse response) throws ServletException, IOException {
 85 
 86         response.setCharacterEncoding("UTF-8");// 設置request和response編碼,兩個都要注意
 87         request.setCharacterEncoding("UTF-8");
 88         String requestURI = request.getRequestURI();// 訪問Servlet的URI
 89         String method = request.getMethod();// 訪問Servlet的方式Get或Post
 90         // 得到用戶提交的全部param
 91         Map<String, String> map = request.getParameterMap();
 92         for (String key : map.keySet()) {
 93             System.out.println(key + "+" + request.getParameter(key));
 94         }
 95 
 96         response.setContentType("text/html");// 設置文檔類型爲HTML類型
 97         PrintWriter out = response.getWriter();
 98         out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
 99         out.println("<HTML>");
100         out.println("<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">");
101         out.println("<HEAD><TITLE>A Servlet</TITLE></HEAD>");
102         out.println(" <BODY>");
103         out.println("    以" + method + " 方式訪問該頁面。提取的param參數爲:<br/>");
104         for (String key : map.keySet()) {
105             out.println("    " + key + "+" + request.getParameter(key) + "<br/>");
106         }
107 
108         out.println("  </BODY>");
109         out.println("</HTML>");
110         out.flush();
111         out.close();
112     }
113 
114     /**
115      * Initialization of the servlet. <br>
116      * 
117      * @throws ServletException
118      *             if an error occurs
119      */
120     public void init() throws ServletException {
121         // Put your code here
122     }
123 
124 }

這裏將doGet和doPost都交給了execute執行,在execute中用request獲取請求的相關信息,用response設置返回信息(這樣若是用瀏覽器訪問該網頁時通常是HTTP的GET或POST請求將觸發doGet或doPost函數,而後最終將請求提交給execute執行處理,在execute中獲取請求信息並用response的response.getWriter()向客戶端寫回信息,這裏因爲是web服務,因此寫回的是一個完整的html文檔,這樣瀏覽器就能根據返回的文檔進行相應顯示啦~)

此外,當咱們添加一個servlet時會發現web.xml中多了些東西:

包括servlet的name和對應的class,特別重要的是下面的servlet-mapping中的url-pattern,這個指明瞭訪問該servlet的地址:在這裏爲http://localhost:8080/beautifulzzzz/servlet/hello


 

part.2 安卓HTTP的POST和GET請求方法

摘自園友lingyun1120關於安卓HTTP的POST和GET的請求的總結:

1.get是從服務器上獲取數據,post是向服務器傳送數據。
2.get是把參數數據隊列加到提交表單的 ACTION屬性所指的URL中,值和表單內各個字段一一對應,在URL中能夠看到。post是經過HTTPpost機制,將表單內各個字段與其內容放置 在HTML HEADER內一塊兒傳送到ACTION屬性所指的URL地址。用戶看不到這個過程。
3.對於get方式,服務器端用 Request.QueryString獲取變量的值,對於post方式,服務器端用Request.Form獲取提交的數據。
4.get 傳送的數據量較小,不能大於2KB。post傳送的數據量較大,通常被默認爲不受限制。但理論上,IIS4中最大量爲80KB,IIS5中爲100KB。
5.get安全性很是低,post安全性較高。

對於安卓HTTP請求的實現主要有兩種方法,一種是傳統的HttpURLConnection 方式,另外一種是HttpClinet方式。

方式一:HttpURLConnection之GET

 1 /***
 2  * 用HttpURLConnection發送Get請求,返回請求字符
 3  * @return
 4  * @throws IOException
 5  */
 6 public String Func1() throws IOException{
 7     // 拼湊get請求的URL字串,使用URLEncoder.encode對特殊和不可見字符進行編碼
 8     String MyURL=BASE_URL+ "?name=" + URLEncoder.encode("beautifulzzzz", "utf-8")
 9             +"&password=12345678";//(好像這裏中文不行)
10     URL getUrl = new URL(MyURL);
11     // 根據拼湊的URL,打開鏈接,URL.openConnection函數會根據URL的類型,
12     // 返回不一樣的URLConnection子類的對象,這裏URL是一個http,所以實際返回的是HttpURLConnection
13     HttpURLConnection conn = (HttpURLConnection) getUrl.openConnection();
14     
15     // 設置鏈接屬性
16     conn.setConnectTimeout(30000);// 設置鏈接超時時長,單位毫秒
17           
18     // 進行鏈接,可是實際上get request要在下一句的connection.getInputStream()函數中才會真正發到服務器
19     BufferedReader reader = new BufferedReader(new InputStreamReader(
20             conn.getInputStream()));// 取得輸入流,並使用Reader讀取
21     String result = "";
22     String line = "";
23     while ((line = reader.readLine()) != null) {
24         result = result + line+"\n";
25     }
26     System.out.println(result);
27     reader.close();
28     conn.disconnect();
29     return result;
30 }

由於Get請求請求的內容是放在URL中的,因此第8行用BASE_URL和想發送的鍵值對合成爲新的URL,而後根據新合成的URL打開連接得到HttpURLConnection,可是真正的get請求是在connection.getInputStream()函數中才會真正發到服務器的,當該函數執行完時會返回一個輸入流,而後咱們使用Reader讀取該輸入流中的內容從而得到服務器的response。

方式二:HttpURLConnection之POST

 1 /***
 2  * 用HttpURLConnection發送post請求,返回請求字符
 3  * @return
 4  * @throws IOException
 5  */
 6 public String Func2() throws IOException {
 7     URL url = new URL(BASE_URL);
 8     // 此處的urlConnection對象其實是根據URL的
 9     // 請求協議(此處是http)生成的URLConnection類
10     // 的子類HttpURLConnection,故此處最好將其轉化
11     // 爲HttpURLConnection類型的對象,以便用到
12     // HttpURLConnection更多的API.以下:
13     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
14 
15     // 設置鏈接屬性
16     conn.setDoOutput(true);// 使用 URL 鏈接進行輸出
17     conn.setDoInput(true);// 使用 URL 鏈接進行輸入
18     conn.setUseCaches(false);// POST請求不能用緩存
19     conn.setConnectTimeout(30000);// 設置鏈接超時時長,單位毫秒
20     conn.setInstanceFollowRedirects(true);// URLConnection.setInstanceFollowRedirects是成員函數,僅做用於當前函數
21     // 配置本次鏈接的Content-type,配置爲application/x-www-form-urlencoded的
22     // 意思是正文是urlencoded編碼過的form參數,下面咱們能夠看到咱們對正文內容使用URLEncoder.encode
23     // 進行編碼
24     conn.setRequestProperty("Content-Type",
25             "application/x-www-form-urlencoded");
26     conn.setRequestMethod("POST");// 設置請求方式,POST or
27                                     // GET,注意:若是請求地址爲一個servlet地址的話必須設置成POST方式
28 
29     OutputStream outStrm = conn.getOutputStream();// 此處getOutputStream會隱含的進行connect
30     DataOutputStream out = new DataOutputStream(outStrm);
31      // 正文,正文內容其實跟get的URL中'?'後的參數字符串一致
32     String content = "name=" + URLEncoder.encode("李某人", "utf-8")
33             +"&password="+ URLEncoder.encode("12345678", "utf-8");
34     // DataOutputStream.writeBytes將字符串中的16位的unicode字符以8位的字符形式寫道流裏面
35     out.writeBytes(content); 
36     out.flush();
37     out.close(); // flush and close
38     
39     // 調用HttpURLConnection鏈接對象的getInputStream()函數,
40     // 將內存緩衝區中封裝好的完整的HTTP請求電文發送到服務端。
41     InputStream inStrm = conn.getInputStream(); // <===注意,實際發送請求的代碼段就在這裏
42     // 上邊的httpConn.getInputStream()方法已調用,本次HTTP請求已結束,再向對象輸出流的輸出已無心義,
43     // 既使對象輸出流沒有調用close()方法,下邊的操做也不會向對象輸出流寫入任何數據.
44     // 所以,要從新發送數據時須要從新建立鏈接、從新設參數、從新建立流對象、從新寫數據、
45     // 從新發送數據(至因而否不用從新這些操做須要再研究)
46     BufferedReader reader = new BufferedReader(
47             new InputStreamReader(inStrm));
48     String result = "";
49     String line = "";
50     while ((line = reader.readLine()) != null) {
51         result = result + line+"\n";
52     }
53     System.out.println(result);
54     reader.close();
55     conn.disconnect();
56     return result;
57 }

對於POST請求和GET不一樣點在於POST的請求正文不是放在URL中。其信息包括請求頭和請求正文,全部關於這次http請求的配置都在http頭裏面定義;對於請求正文content,在connect()函數裏面,會根據HttpURLConnection對象的配置值生成http頭,所以在調用connect函數以前,就必須把全部的配置準備好(可是若是使用了conn.getInputStream()函數就能夠不用使用connect()函數了)。

緊接着http頭的是http請求的正文,正文的內容經過outputStream寫入,實際上outputStream不是一個網絡流,充其量是個字符串流,往裏面寫入的東西不會當即發送到網絡,而是在流關閉後,根據輸入的內容生成http正文。

至此,http請求的東西已經準備就緒。在getInputStream()函數調用的時候,就會把準備好的http請求正式發送到服務器了,而後返回一 個輸入流,用於讀取服務器對於這次http請求的返回信息。因爲http請求在getInputStream的時候已經發送出去了(包括http頭和正 文),所以在getInputStream()函數以後對connection對象進行設置(對http頭的信息進行修改)或者寫入 outputStream(對正文進行修改)都是沒有意義的了,執行這些操做會致使異常的發生。

注:這裏要注意24和35行,若是設置不對會致使服務器沒法獲取鍵值對!

注:上面一段參考博客pandazxx的專欄:[Http學習之使用HttpURLConnection發送post和get請求 ]

方式三:HttpClinet之GET

 1 /***
 2  * 使用Http的GET請求返回服務器返回結果字符串
 3  * 
 4  * @return
 5  * @throws ClientProtocolException
 6  * @throws IOException
 7  */
 8 public String Func3() throws ClientProtocolException, IOException {
 9     HttpGet httpGet = new HttpGet(BASE_URL + "?name=beautifulzzzz"
10             + "&password=1234");
11     // 獲取HttpClient對象
12     HttpClient httpClient = new DefaultHttpClient();
13     // 鏈接超時
14     httpClient.getParams().setParameter(
15             CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
16     // 請求超時
17     httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
18             30000);
19     HttpResponse httpResp = httpClient.execute(httpGet);
20     String response = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
21     System.out.println(response);
22     if (response == null)
23         response = "";
24     return response;
25 }

當使用HttpClient發送Get請求時則相對簡單,可是從第9行仍是能夠看出Get請求的消息仍是放在URL中的,特別的這裏是實例化一個HttpGet請求,並用HttpClient對象進行相關屬性配置,而後調用execute函數得到服務器返回HttpResponse,而後調用getEntity()函數獲取Httpresponse實體內容。

方式四:HttpClinet之POST

 1 /***
 2  * 使用Http的POST請求返回服務器返回結果字符串
 3  * 
 4  * @return
 5  * @throws ClientProtocolException
 6  * @throws IOException
 7  */
 8 public String Func4() throws ClientProtocolException, IOException {
 9     // 將用戶名、密碼和imei封裝到list中,待http發送post請求給服務器
10     NameValuePair pair1 = new BasicNameValuePair("user_name", "濤");
11     NameValuePair pair2 = new BasicNameValuePair("user_password",
12             "Deddd344");
13     List<NameValuePair> pairList = new ArrayList<NameValuePair>();
14     pairList.add(pair1);
15     pairList.add(pair2);
16     HttpPost httpPost = new HttpPost(BASE_URL);
17     HttpEntity requestHttpEntity = new UrlEncodedFormEntity(pairList,
18             HTTP.UTF_8);
19     // 將請求體內容加入請求中
20     httpPost.setEntity(requestHttpEntity);
21     // 獲取HttpClient對象
22     HttpClient httpClient = new DefaultHttpClient();
23     // 鏈接超時
24     httpClient.getParams().setParameter(
25             CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
26     // 請求超時
27     httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
28             30000);
29 
30     HttpResponse httpResp = httpClient.execute(httpPost);
31     String response = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
32     System.out.println(response);
33     if (response == null)
34         response = "";
35     return response;
36 }

對於HttpClinet發送POST請求,由於鍵值不是保存在URL中,因此這裏要用NameValuePair構建鍵值對,而後用List<NameValuePair>存儲這些鍵值對,並用此List構建一個HttpEntity實體信息,而後調用httpPost.setEntity(requestHttpEntity);將實體信息加入httpPost中,接着同Get利用execute執行POST請求,而後調用getEntity()得到服務器返回的實體信息。


 

part.3 本例中C/S雙方工做機制分析

以下圖:本文的安卓客戶端分別用上述講的四種方法向本地的Java Web進行訪問,圖中顯示爲執行URI_GET請求時的客戶端和服務器後臺的效果:點擊URI_GET按鈕-->客戶端啓動Quest(1)線程使用Func1()進行Get請求-->當請求結束經過Message將從Func1()返回的服務器返回的Response字符串傳送給消息接收句柄,在消息接受句柄中進行對UI中的TextView更新,顯示返回結果。而服務器端如part1中介紹,當接收到客戶端的POST或GET請求時,都會委託給execute函數來處理,並用PrintWriter out = response.getWriter();將消息發給客戶端。


 

part.4 拓展知識

拓展知識均來自網絡:請支持原創做者。
http://www.apkbus.com/android-13575-1-1.html
第一種版本:

  • HTTP 定義了與服務器交互的不一樣方法,最基本的方法是 GET 和 POST。
  • 事實上 GET 適用於多數請求,而保留 POST 僅用於更新站點。根據 HTTP 規範,GET 用於信息獲取,並且應該是 安全的和 冪等的。所謂安全的意味着該操做用於獲取信息而非修改信息。換句話說,GET 請求通常不該產生反作用。冪等的意味着對同一 URL 的多個請求應該返回一樣的結果。完整的定義並不像看起來那樣嚴格。從根本上講,其目標是當用戶打開一個連接時,它能夠確信從自身的角度來看沒有改變資源。 好比,新聞站點的頭版不斷更新。雖然第二次請求會返回不一樣的一批新聞,該操做仍然被認爲是安全的和冪等的,由於它老是返回當前的新聞。反之亦然。
  • POST 請求就不那麼輕鬆了。POST 表示可能改變服務器上的資源的請求。仍然以新聞站點爲例,讀者對文章的註解應該經過 POST 請求實現,由於在註解提交以後站點已經不一樣了(比方說文章下面出現一條註解);
  • 在FORM提交的時候,若是不指定Method,則默認爲GET請求,Form中提交的數據將會附加在url以後,以?分開與url分開。字母數字字符原 樣發送,但空格轉換爲「+「號,其它符號轉換爲%XX,其中XX爲該符號以16進製表示的ASCII(或ISO Latin-1)值。GET請求請提交的數據放置在HTTP請求協議頭中,而POST提交的數據則放在實體數據中;
  • GET方式提交的數據最多隻能有1024字節,而POST則沒有此限制。 

第二種版本:

  • get是從服務器上獲取數據,post是向服務器傳送數據。
  • 在客戶端,Get方式在經過URL提交數據,數據在URL中能夠看到;POST方式,數據放置在HTML HEADER內提交。
  • 對於get方式,服務器端用Request.QueryString獲取變量的值,對於post方式,服務器端用Request.Form獲取提交的數據。
  • GET方式提交的數據最多隻能有1024字節,而POST則沒有此限制。
  • 安全性問題。正如在(1)中提到,使用 Get 的時候,參數會顯示在地址欄上,而 Post 不會。因此,若是這些數據是中文數據並且是非敏感數據,那麼使用 get;若是用戶輸入的數據不是中文字符並且包含敏感數據,那麼仍是使用 post爲好。

第三種版本:

  • Get是用來從服務器上得到數據,而Post是用來向服務器上傳遞數據。
  • Get將表單中數據的按照variable=value的形式,添加到action所指向的URL後面,而且二者使用「?」鏈接,而各個變量之間使用 「&」鏈接;Post是將表單中的數據放在form的數據體中,按照變量和值相對應的方式,傳遞到action所指向URL。
  • Get是不安全的,由於在傳輸過程,數據被放在請求的URL中,而現在現有的不少服務器、代理服務器或者用戶代理都會將請求URL記錄到日誌文件中,而後 放在某個地方,這樣就可能會有一些隱私的信息被第三方看到。另外,用戶也能夠在瀏覽器上直接看到提交的數據,一些系統內部消息將會一同顯示在用戶面前。 Post的全部操做對用戶來講都是不可見的。
  • Get傳輸的數據量小,這主要是由於受URL長度限制;而Post能夠傳輸大量的數據,因此在上傳文件只能使用Post(固然還有一個緣由,將在後面的提到)。
  • Get限制Form表單的數據集的值必須爲ASCII字符;而Post支持整個ISO10646字符集。
  • Get是Form的默認方法。

 

相關連接

此外推薦一些連接幫助更好理解安卓GET和POST請求:

一、個人漫漫程序之旅:[http://www.blogjava.net/supercrsky/articles/247449.html]

內容提示:給出了JDK中的URLConnection參數詳解,寫的很詳細,能幫助理解URLConnection

二、pandazxx的專欄:[http://blog.csdn.net/pandazxx/article/details/1657109]

內容提示:Http學習之使用HttpURLConnection發送post和get請求 ,有例子,有註釋

三、上述工程C/S代碼:[http://pan.baidu.com/s/1qWqNUos]

四、上述工程GitHub:[https://github.com/beautifulzzzz/Android/tree/master/HTTP_POST_GET]

相關文章
相關標籤/搜索