1. 程式人生 > >java實現網路互動 get、post方法

java實現網路互動 get、post方法

終於把要上的課都上完了,強度太大了,累的連部落格都懶得寫了,很久都沒寫過了。。。不過現在得開始逐步總結了!

由於近期主要在學網路互動這一塊,那麼這裡就從最基礎的java實現get、post請求說起吧:

首先我們得了解http get和post的請求方式,
1、get方式下,URL地址後的附加資訊;
瀏覽器在URL地址後以“?”形式帶上資料,多個數據之間以&分隔如:http://localhost:8080/MyApp/myServlet?name1=value1&age=value2

請求示例:
GET /myApp/1.html?name=tom&age=21 HTTP/1.1
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Host: localhost:8080
Connection: Keep-Alive

2、post方式下,HTTP請求訊息中的實體內容部分;
<form>表單method屬性設定為“post”,提交表單時生成的HTTP請求方式:Content-Type: application/x-www-form-urlencoded
POST方式傳遞引數的形式:作為請求訊息的實體內容部分進行傳送

請求示例:
POST /myApp/1.html HTTP/1.1
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Host: localhost:8080
Connection: Keep-Alive

name=tom&age=21

下來用java程式碼實現:

1、我們先用最底層的Socket來實現:
get方法:
Socket socket = new Socket("localhost",8080);		
	StringBuffer sb = new StringBuffer();
	sb.append("POST /Servlett?name=tom&age=21 HTTP/1.1\r\n");//請求地址和引數
	sb.append("Connection: close\r\n");//連線狀態
	sb.append("Host: localhost:8080\r\n");//網路地址,埠
	sb.append("\r\n");
	socket.getOutputStream().write(sb.toString().getBytes());//傳送到伺服器

post方法:

StringBuffer sb = new StringBuffer();
	sb.append("POST /Servlett HTTP/1.1\r\n");
	sb.append("Connection: close\r\n");
	sb.append("Host: localhost:8080\r\n");
	sb.append("Content-Type: application/x-www-form-urlencoded\r\n");//引數內容
	sb.append("\r\n");
			
	sb.append("name=tom&age=21");
			
	socket.getOutputStream().write(sb.toString().getBytes());

要接受伺服器端發過來的資訊,直接用InputStream獲取就行,再進行處理,ye可以用下面要說到的的formatIsToString()方法將結果處理為String型別

其實到這裡應該很清楚get方式和post方式的不同之處了,因為get方法將引數(使用者資料)放在url中,在瀏覽器中很容易得到,極不安全;而post方法將引數置於內容之中,在請求過程中不會被發現,是安全的。所以在web專案中一般關於使用者資訊的提交方式都是post。

2、其實 在java中有個類:HttpURLConnection 它已經把這些東西封裝好了,我們可以用它來實現
首先我們需要一個將InputStream物件轉為String物件的方法(簡單寫一種)
public static String formatIsToString(InputStream is)throws Exception{
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			byte[] buf = new byte[1024];
			int len = -1;
			try {
				while( (len=is.read(buf)) != -1){
					baos.write(buf, 0, len);
				}
				baos.flush();
				baos.close();
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return new String(baos.toByteArray(),"utf-8");
		}

get方法實現:
public static String get(String apiUrl) throws Exception {
		String str= null;
		URL url = new URL(apiUrl);
		
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		con.setReadTimeout(5000);//將讀超時設定為指定的超時,以毫秒為單位。用一個非零值指定在建立到資源的連線後從 Input 流讀入時的超時時間。如果在資料可讀取之前超時期滿,則會引發一個 java.net.SocketTimeoutException。
		con.setDoInput(true);//指示應用程式要從 URL 連線讀取資料。
		con.setRequestMethod("GET");//設定請求方式
		if(con.getResponseCode() == 200){//當請求成功時,接收資料(狀態碼“200”為成功連線的意思“ok”)
			InputStream is = con.getInputStream();
			str = formatIsToString(is);
		}
		return str;
	}


post方法實現:

將請求的引數內容放在一個Map中,在傳送之前需要解析它(在這用的是下面的getContent()方法)

public static String post(String apiUrl,
			HashMap<String, String> params) throws Exception {
		String str = null;
		URL url = new URL(apiUrl);//根據引數建立URL物件
		HttpURLConnection con = (HttpURLConnection) url.openConnection();//得到HttpURLConnection物件
		con.setRequestMethod("POST");
		con.setReadTimeout(5000);
		con.setDoInput(true);
		con.setDoOutput(true);//指示應用程式要將資料寫入 URL 連線。
		String content = getContent(params);//解析引數(請求的內容)
		con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//設定內容
		con.setRequestProperty("Content-Length", content.length()+"");//設定內容長度
		OutputStream os = con.getOutputStream();
		os.write(content.getBytes("utf-8"));//傳送引數內容
		os.flush();
		os.close();
		if(con.getResponseCode() == 200){
			str = formatIsToString(con.getInputStream());
		}
		return str;
	}

將map裡的引數進行解析
private static String getContent(HashMap<String, String> params) throws UnsupportedEncodingException {
		String content = null;
		Set<Entry<String,String>> set = params.entrySet();//Map.entrySet 方法返回對映的 collection 檢視,其中的元素屬於此類
		StringBuilder sb = new StringBuilder();
		for(Entry<String,String> i: set){//將引數解析為"name=tom&age=21"的模式
			sb.append(i.getKey()).append("=")
			.append(URLEncoder.encode(i.getValue(), "utf-8"))
			.append("&");
		}
		if(sb.length() > 1){
			content = sb.substring(0, sb.length()-1);
		}
		return content;
	}
用Entry的好處是不用知道key的值可以通過getKey()和getValue()方法得到map中的所有值