內容簡介html
本文經過創建一個簡單的Servlet服務器來分析安卓上用HTTP和服務器通訊的細節,旨在演示C/S模式下服務器端和客戶端的工做過程。java
目錄android
part.1 用MyEclipse創建一個簡單的servlet服務器git
part.2 安卓HTTP的POST和GET請求方法github
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
摘自園友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()得到服務器返回的實體信息。
以下圖:本文的安卓客戶端分別用上述講的四種方法向本地的Java Web進行訪問,圖中顯示爲執行URI_GET請求時的客戶端和服務器後臺的效果:點擊URI_GET按鈕-->客戶端啓動Quest(1)線程使用Func1()進行Get請求-->當請求結束經過Message將從Func1()返回的服務器返回的Response字符串傳送給消息接收句柄,在消息接受句柄中進行對UI中的TextView更新,顯示返回結果。而服務器端如part1中介紹,當接收到客戶端的POST或GET請求時,都會委託給execute函數來處理,並用PrintWriter out = response.getWriter();將消息發給客戶端。
拓展知識均來自網絡:請支持原創做者。
http://www.apkbus.com/android-13575-1-1.html
第一種版本:
第二種版本:
第三種版本:
相關連接
此外推薦一些連接幫助更好理解安卓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]