1. 程式人生 > >Android使用HttpUrlConnection請求伺服器傳送資料詳解

Android使用HttpUrlConnection請求伺服器傳送資料詳解

HttpUrlConnection是java內建的api,在java.net包下,那麼,它請求網路同樣也有get請求和post請求兩種方式。最常用的Http請求無非是get和post,get請求可以獲取靜態頁面,也可以把引數放在URL字串後面,傳遞給servlet,post與get的不同之處在於post的引數不是放在URL字串裡面,而是放在http請求的正文內。

在Java中可以使用HttpURLConnection發起這兩種請求,瞭解此類,對於瞭解soap,和編寫servlet的自動測試程式碼都有很大的幫助。

一、那麼我們先來看看用HttpUrlConnection怎樣用Post發起請求傳輸json資料(這裡以常用的json作為示例):

public void httpUrlConnPost(String name,String password){
		HttpURLConnection urlConnection = null;
		URL url = null;
		try {
			 url = new URL("http://192.168.1.105:8080/KYDServer/servlet/Login");
			 urlConnection = (HttpURLConnection) url.openConnection();//開啟http連線
			 urlConnection.setConnectTimeout(3000);//連線的超時時間
			 urlConnection.setUseCaches(false);//不使用快取
			 //urlConnection.setFollowRedirects(false);是static函式,作用於所有的URLConnection物件。
			 urlConnection.setInstanceFollowRedirects(true);//是成員函式,僅作用於當前函式,設定這個連線是否可以被重定向
			 urlConnection.setReadTimeout(3000);//響應的超時時間
			 urlConnection.setDoInput(true);//設定這個連線是否可以寫入資料
			 urlConnection.setDoOutput(true);//設定這個連線是否可以輸出資料
			 urlConnection.setRequestMethod("POST");//設定請求的方式
			 urlConnection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");//設定訊息的型別
			 urlConnection.connect();// 連線,從上述至此的配置必須要在connect之前完成,實際上它只是建立了一個與伺服器的TCP連線
			 JSONObject json = new JSONObject();//建立json物件
			 json.put("name", URLEncoder.encode(name, "UTF-8"));//使用URLEncoder.encode對特殊和不可見字元進行編碼
			 json.put("password", URLEncoder.encode(password, "UTF-8"));//把資料put進json物件中
			 String jsonstr = json.toString();//把JSON物件按JSON的編碼格式轉換為字串
			 //-------------使用位元組流傳送資料--------------			 
			 //OutputStream out = urlConnection.getOutputStream();
			 //BufferedOutputStream bos = new BufferedOutputStream(out);//緩衝位元組流包裝位元組流
			 //byte[] bytes = jsonstr.getBytes("UTF-8");//把字串轉化為位元組陣列
			 //bos.write(bytes);//把這個位元組陣列的資料寫入緩衝區中
			 //bos.flush();//重新整理緩衝區,傳送資料
			 //out.close();
			 //bos.close();
			 //------------字元流寫入資料------------
			 OutputStream out = urlConnection.getOutputStream();//輸出流,用來發送請求,http請求實際上直到這個函式裡面才正式傳送出去
			 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));//建立字元流物件並用高效緩衝流包裝它,便獲得最高的效率,傳送的是字串推薦用字元流,其它資料就用位元組流
			 bw.write(jsonstr);//把json字串寫入緩衝區中
			 bw.flush();//重新整理緩衝區,把資料傳送出去,這步很重要
			 out.close();
			 bw.close();//使用完關閉
			 
			 if(urlConnection.getResponseCode()==HttpURLConnection.HTTP_OK){//得到服務端的返回碼是否連線成功
				 //------------位元組流讀取服務端返回的資料------------				 
				 //InputStream in = urlConnection.getInputStream();//用輸入流接收服務端返回的迴應資料
				 //BufferedInputStream bis = new BufferedInputStream(in);//高效緩衝流包裝它,這裡用的是位元組流來讀取資料的,當然也可以用字元流
				 //byte[] b = new byte[1024];
				 //int len = -1;
				 //StringBuffer buffer = new StringBuffer();//用來接收資料的StringBuffer物件
				 //while((len=bis.read(b))!=-1){
				 //buffer.append(new String(b, 0, len));//把讀取到的位元組陣列轉化為字串
				 //}
				 //in.close();
				 //bis.close();
				 //Log.d("zxy", buffer.toString());//{"json":true}
				 //JSONObject rjson = new JSONObject(buffer.toString());//把返回來的json編碼格式的字串資料轉化成json物件
				 //------------字元流讀取服務端返回的資料------------					
				 InputStream in = urlConnection.getInputStream();
				 BufferedReader br = new BufferedReader(new InputStreamReader(in));
				 String str = null;
				 StringBuffer buffer = new StringBuffer();
				 while((str = br.readLine())!=null){//BufferedReader特有功能,一次讀取一行資料
					 buffer.append(str);
				 }
				 in.close();
				 br.close();
				 JSONObject rjson = new JSONObject(buffer.toString());
				 
				 Log.d("zxy", "rjson="+rjson);//rjson={"json":true}
				 boolean result = rjson.getBoolean("json");//從rjson物件中得到key值為"json"的資料,這裡服務端返回的是一個boolean型別的資料
				 if(result){//判斷結果是否正確
					 mHandler.sendEmptyMessage(USERLOGIN_SUCCESS);
				 }else{
					 mHandler.sendEmptyMessage(USERLOGIN_FAILED);
				 }
			 }else{
				 mHandler.sendEmptyMessage(USERLOGIN_FAILED);
			 }
		} catch (Exception e) {
			 mHandler.sendEmptyMessage(USERLOGIN_FAILED);
		}finally{
			urlConnection.disconnect();//使用完關閉TCP連線,釋放資源
		}
	}

服務端的程式碼為:(使用HttpUrlConnection,服務端是用輸入流來讀取客戶端發過來的資料。而使用HttpClient的話,則服務端用相應的key值來獲取資料)

public void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		System.out.println(request.getContentType());//得到客戶端傳送過來內容的型別,application/json;charset=UTF-8
		System.out.println(request.getRemoteAddr());//得到客戶端的ip地址,192.168.1.101
		//------------使用位元組流讀取客戶端傳送過來的資料------------
		// BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
		// byte[] b = new byte[1024];
		// int len=-1;
		// StringBuffer buffer = new StringBuffer();
		// while((len=bis.read(b))!=-1){
		// buffer.append(new String(b, 0, len));
		// }
		// bis.close();
		// System.out.println("buffer="+buffer);
		// JSONObject json = JSONObject.fromObject(buffer.toString());

		BufferedReader br = new BufferedReader(new InputStreamReader(//使用字元流讀取客戶端發過來的資料
				request.getInputStream()));
		String line = null;
		StringBuffer s = new StringBuffer();
		while ((line = br.readLine()) != null) {
			s.append(line);
		}
		br.close();
		System.out.println(s.toString());//{"password":"123456","name":"admin"}
		JSONObject json = JSONObject.fromObject(s.toString());//轉化為jSONObject物件

		String name = json.getString("name");//從json物件中得到相應key的值
		String password = json.getString("password");
		
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json;charset=UTF-8");
		if (name.equals("admin") && password.equals("123456")) {
			JSONObject rjson = new JSONObject();
			rjson.put("json", true);//返回boolean型別的值
			System.out.println("rjson=" + rjson);
			// response.getWriter().write(rjson.toString());//向客戶端傳送一個帶有json物件內容的響應
			response.getOutputStream().write(rjson.toString().getBytes("UTF-8"));//向客戶端傳送一個帶有json物件內容的響應
		} else {
			JSONObject rjson = new JSONObject();
			rjson.put("json", false);
			System.out.println("rjson=" + rjson);
			// response.getWriter().write(rjson.toString());//向客戶端傳送一個帶有json物件內容的響應
			response.getOutputStream().write(rjson.toString().getBytes("UTF-8"));//向客戶端傳送一個帶有json物件內容的響應
		}
	}

二、我們再來看看用Get請求:
public void httpUrlConnGet(String name,String password){
		HttpURLConnection urlConnection = null;
		URL url = null;
		try {
			String urlStr = "http://192.168.1.105:8080/KYDServer/servlet/Login?name="+name+"&password="+password;
			url = new URL(urlStr);
			urlConnection = (HttpURLConnection) url.openConnection();
			urlConnection.connect();
			if(urlConnection.getResponseCode()==HttpURLConnection.HTTP_OK){
				InputStream in = urlConnection.getInputStream();
				BufferedReader br = new BufferedReader(new InputStreamReader(in));
				String line = null;
				StringBuffer buffer = new StringBuffer();
				while((line=br.readLine())!=null){
					buffer.append(line);
				}
				in.close();
				br.close();
				String result = buffer.toString();
				if(result.equals("ok")){
					mHandler.sendEmptyMessage(USERLOGIN_SUCCESS);
				}else{
					mHandler.sendEmptyMessage(USERLOGIN_FAILED);
				}
			}else{
				mHandler.sendEmptyMessage(CONN_FIALED);
			}
		} catch (Exception e) {
			mHandler.sendEmptyMessage(CONN_FIALED);
		}finally{
			urlConnection.disconnect();
		}
	}
Get請求的服務端程式碼我就不寫啦,但是服務端是用key值來獲取資料的哦,這個和post的方式不同。

所以總結一下:

  • 使用HttpUrlConnection請求伺服器的話:

用Get請求:客戶端的資料是放在url中的,通過url來傳給伺服器。服務端接收客戶端發來的資料是用對應的key值的,服務端返回資料給客戶端是用response.getWriter().write()或response.getOutputStream().write()來返回的,客戶端接收服務端返回來的資料是用urlConnection.getInputStream()輸入流來讀取的。

用Post請求:客戶端的資料是放在正文中的,即是通過urlConnection.getOutputStream()輸出流來發送給伺服器的。服務端接收客戶端發來的資料是用request.getInputStream()輸入流來讀取的,服務端返回資料給客戶端是用response.getWriter().write()或response.getOutputStream().write()來返回的客戶端接收服務端返回來的資料是用urlConnection.getInputStream()輸入流來讀取的。【注】:使用HttpUrlConnection客戶端的傳送和接收資料都是用流操作的。

  • 使用HttpClient請求伺服器的話:

用Get請求:客戶端的資料是放在url中的,通過url傳給伺服器。服務端接收客戶端發來的資料是用對應的key值的,服務端返回資料給客戶端是用response.getWriter().write()或response.getOutputStream().write()來返回的,客戶端接收服務端返回來的資料是用

response.getEntity()來接收。

用Post請求:客戶端的資料是放在List<NameValuePair>parameters集合中,通過post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8"))傳送給伺服器。服務端接收客戶端發來的資料是用對應的key值的,服務端返回資料給客戶端是用response.getWriter().write()或response.getOutputStream().write()來返回的客戶端接收服務端返回來的資料是用

response.getEntity()來接收。


HttpURLConnection.connect()函式,實際上只是建立了一個與伺服器的tcp連線,並沒有實際傳送http請求。無論是post還是get,http請求實際上直到HttpURLConnection.getInputStream()這個函式裡面才正式傳送出去。

在HttpUrlConnection
中,順序是重中之重,對urlConnection物件的一切配置(那一堆set函式)都必須要在connect()函式執行之前完成。

http請求實際上由兩部分組成,一個是http頭,所有關於此次http請求的配置都在http頭裡面定義,另一個是正文content。在connect()函式裡面,會根據HttpURLConnection物件的配置值生成http頭,因此在呼叫connect函式之前,就必須把所有的配置準備好。
緊接著http頭的是http請求的正文,正文的內容通過outputStream寫入,實際上outputStream不是一個網路流,充其量是個字串流,往裡面寫入的東西不會立即傳送到網路,而是在流關閉後,根據輸入的內容生成http正文。

轉載請註明出處!!!