1. 程式人生 > >Java Sokect程式設計之HTTP請求

Java Sokect程式設計之HTTP請求

1、概述

  HTTP是一種協議,全稱超文字傳輸協議,而網頁就屬於超文字(就是為了它服務的),可以支援多媒體等,比如圖片、音訊,豐富了使用者的體驗;它屬於網路模型中應用層的協議,底層基於TCP/IP協議,並額外製定了自己的規範,所以它也是Socket程式設計的一種,只是由於強大和便捷的客戶端和服務端軟體,常常讓人看不到它的本質。


  首先HTTP屬於網路程式設計,而且是基於TCP/IP協議的,那麼它一定有兩個Socket端點,所以具備的基本要素有:
    • 客戶端:瀏覽器,比如IE、Chrome、FireFox、360等
    • 服務端:Web伺服器,有Tomcat、Weblogic等
    • 第三個往往會被忽視的:網址,專業術語URL,它包含了網路傳輸的基本要素:協議、IP、埠等。

2、最簡單的方式實現HTTP請求

 2.1 最簡單的方式是什麼?

   對普通使用者來說,HTTP請求這個名詞顯得有點專業和陌生,而用“上網“或者更精確的講”使用瀏覽器上網“,更能讓人有恍然大悟的感覺,你可能覺得何必搞怎麼一個標題呢,那只是我們沒有了解到實現HTTP請求可不僅僅只有這種方式,至於還有那些方式,當了解到它的原理就自然清楚了。

   即使最簡單和熟悉的HTTP請求方式(上網),對軟體人員來說,也需要更加專業的去分析它,通過不同的視角和見解,更加透視的看清它的內在。 

 2.2 流程圖

 通過瀏覽器實現HTTP請求的基本流程如下:


 2.3 URL(見Java API:java.net.URL)

2.3.1 概述

  Uniform Resource Locator,中文翻譯,統一資源定位符,它是指向網際網路"資源"的指標。資源可以是簡單的檔案或目 錄,也可以是對更復雜物件的引用,例如對資料庫或搜尋引擎的查詢。它的組成是有一定規則的,是資訊的一種集合,一般由協議名、主機、埠、資源組成,格式如下:
  protocol://host:port//resourceName,比如:http://www.crazyit.org/index.php,當然URL不僅僅支援http這一種 協議,比如https、ftp等。
  有了它以後,客戶端就可以對它進行解析,比如網路通訊的基本要素:協議、IP、埠,都可以拿到,這樣才能確定通訊的目的地,而通過一個簡單URL就可以對這些內容進行封裝,是不是很方便呢。

2.3.2 URL常用方法:

String getProtocol(),獲取URL的協議名稱。
String getHost(),獲取URL的主機名。
String getPort(), 獲取URL的埠號。
String getPath(), 獲取URL的路徑名稱
String getFile() ,獲取此URL的檔名稱
String getQuery ,獲取此URL的查詢部分。
package com.example.network.http;

import java.net.MalformedURLException;
import java.net.URL;

public class URLDemo {

	public static void main(String[] args) throws MalformedURLException {
		
		String str_url = "http://google.com.hk/search?q=1";
		
		//1.把字串封裝為URL,會丟擲MalformedURLException異常。
		URL url = new URL(str_url);
		
		System.out.println("getProtocol:"+url.getProtocol());
		System.out.println("getHost:"+url.getHost());
		System.out.println("getPort:"+url.getPort());
		System.out.println("getPath:"+url.getPath());
		//getFile() = getPath() + getQuery
		System.out.println("getFile:"+url.getFile());
		System.out.println("getQuery:"+url.getQuery());

	}

}


結果:

getProtocol:http
getHost:google.com.hk
getPort:-1
getPath:/search
getFile:/search?q=1
getQuery:q=1

2.3.3 URL、URI、URN區別?

  URI是統一資源識別符號,總體來說,每一個URL都是URI,但不是每一個URI都是URL。這是因為URI還包括一個子類,即統一 資源名稱(URN),它命名資源但不知道如何定位資源,比如:mailto:[email protected]

2.4 瀏覽器做了哪些工作?

2.4.1 概述

  對於TCP/IP協議而言,只需明確IP、埠號及傳輸的資料,而要弄清楚HTTP協議與此有什麼不同,就需要看看瀏覽器到底給伺服器傳送了什麼資料,那麼怎麼去檢視呢?既然HTTP是基於TCP/IP協議,完全可以通過ServerSocket物件實現一個伺服器,接收瀏覽器的訪問,並打印出接收到的資料。

2.4.2 程式碼示例

1、伺服器程式碼:

package com.example.network.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class MyHttpServer {

	public static void main(String[] args) throws IOException {

		ServerSocket ss = new ServerSocket(8090);
		
		Socket s = ss.accept();
		
		InputStream in = s.getInputStream();
		
		byte[] buf = new byte[1024];
		
		int len = in.read(buf);
		
		System.out.println(new String(buf,0,len));
		
		OutputStream out = s.getOutputStream();
		
		out.write("<font color=red>歡迎訪問Http伺服器!</font>".getBytes());
		
		s.close();
		ss.close();
	}

}

2、在瀏覽器中輸入伺服器地址並回車。

3、檢視瀏覽器的返回內容和伺服器的控制檯輸出。



  正如控制檯中打印出來的訊息,瀏覽器不僅僅只是簡單的接收一個URL,它需要解析這個URL,並且組裝出控制檯中格式化資料,並且把它發給伺服器,伺服器接收請求並且返回應答訊息,最後瀏覽器行使另外一個強大的功能:解析資料,如上所示我給返回字型添加了一個紅色屬性,最終瀏覽器解析並顯出來。

2.4.3、傳送訊息的組成分析。

傳送的訊息分為三部分:


圖中紅色1表示:訊息行,分為三部分:

請求方式:GET和POST。

請求的資源:遺憾的是隻看到一個/,它表示無,因為我沒有指定,實際它是指URL的getFile()的內容。

協議版本:目前有HTTP 1.0和HTTP 1.1。

圖中紅色2表示:訊息頭,它主要以鍵值對的方式顯示,向伺服器傳遞了該瀏覽器的一些屬性,以便於伺服器返回瀏覽器支援的資料,比如:

Accept:瀏覽器支援的格式,如text(文字)、HTML、XML等。

Accpet-Language:瀏覽器支援的語言:zh-CN,簡體中文;zh 中文;en 英文等

Host:主機地址

這些內容還沒有深入的瞭解,只是做簡單的介紹。

圖中紅色3表示:訊息體,可惜是空白,那它是什麼?看完下面章節就知道了。

2.4.1 怎麼向伺服器傳送個人資料。

  不知道你發現一個問題沒有,雖然瀏覽器給伺服器傳送了資料,但是這些資料都是規範化的,如果想給伺服器傳送點自己的資料怎麼辦呢?

  比如想登入某個網站,必須把客戶端填寫的使用者名稱和密碼傳送給伺服器;或者在搜尋引擎中查詢某個關鍵詞,也需要把這個關鍵詞傳送到伺服器進行檢索。

  以一個簡單的表單提交為例,看看瀏覽器到底怎麼向伺服器傳送資料。

 1、提交表單。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登入資訊</title>
</head>
<body>
	<form method="get" action="http://localhost:8090" >
		<table border="1">
			<tr><td>使用者名稱:</td><td ><input name=name type="text"/></td></tr>
			<tr><td>密 碼:</td><td ><input name=pass type="password"/></td></tr>
			<tr><th colspan="2"><input type="submit" value="登入"/></th></tr>
		</table>
	</form>
</body>
</html>

 2、伺服器程式碼還是上面2.5.1中的第一段程式碼。

 3、假定在表單中填寫使用者名稱和密碼。

4、提交後,檢視伺服器控制檯內容。

  你會發現最後多了一行,而這一行的內容就是你在表單中輸入的使用者名稱和密碼,它以鍵值對的方式儲存資料,並且每一組用&符號連線;另外,這一行也屬於之前所說的訊息體,注意訊息體與訊息頭之間有一個空行。

2.4.2 GET和POST區別

  你可能還注意到的一個細節就是在第一行中,請求方式是POST而不是GET,那麼GET和POST到底有什麼區別?你只需把表單以get的方式提交一次就會發現了。

  首先,把第1塊提交表單程式碼中method=“post”改為method=“get”,然後再重新執行一遍上面的流程,你會發現如下區別:

  • 控制檯中最後一行的訊息體沒有了,而第一行POST變為GET,並且請求資源變為“/?name=noodles$pass=26”,如下圖:

  • 第二個不易察覺的變化就是在位址列中多了點東西,就是你的使用者名稱和密碼的資訊,如下圖:

  所以提交個人資料的方式與請求方式密切相關,如果是POST方法,提交的資料將放置在訊息體中;而GET方式,提交的資料將放置在位址列(URL)中。

  這個特點導致GET方式提交資料存在幾個缺點:

  1、資料不安全,假如你登入一個網站時,別人站在你後面,就可以通過位址列檢視到你使用者名稱和密碼,是不是很可怕。

  2、位址列的空間太小。

  所以,如果是提交重要的資料一般都是通過POST的方式,當然不是提交資料都用POST方式,通過google或者baidu檢索資訊時,就是以get的方式提交資料,你可以通過位址列查到查詢的資訊。

 2.6 HTTP伺服器向客戶端返回了什麼內容?

    通過上面的內容,我們已經瞭解到客戶端瀏覽器做了哪些工作,現在就要進一步瞭解服務端到底做為了什麼,或者準確的講伺服器給瀏覽器返回了什麼資訊,怎麼去檢視呢?

    這就需要我們去實現一個瀏覽器,然後我們模仿瀏覽器給伺服器傳送相同的訊息,最後打印出伺服器返回的資料。

    1、你需要一個HTTP伺服器,比如Tomcat,安裝後,在webapp下建立一個myweb檔案下,裡面放置一個mypage.html檔案。

mypage.html程式碼非常簡單,如下:

<html>
<head>
	<meta charset="utf-8">
</head>
<body>
	<a href ="http://www.google.com">Goto Google</a>
</body>
</html>

2、我的瀏覽器程式碼

package com.example.network.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class MyBrowser {

	public static void main(String[] args) throws  IOException {

		//與伺服器建立連線
		Socket s = new Socket("127.0.0.1",8080);
		
		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		
		//模仿瀏覽器向伺服器傳送資料,下面三行是必須的,其他訊息頭資訊可以根據需要傳送,如果不設定,會以預設值傳送(未驗證)。
		out.println("GET /myweb/mypage.html HTTP/1.1");	
		out.println("Host: localhost:8090");		
		out.println();
		
		
		//讀取伺服器返回的資料並列印
		InputStream in = s.getInputStream();
		
		byte[] buf = new byte[1024];
		
		int len = in.read(buf);
		
		System.out.println(new String(buf,0,len));
		
		s.close();
		
		
		
	}

}

3、執行我的瀏覽器程式碼,檢視控制檯資訊,如下:

同樣分為三部分:

圖中紅色1表示:應答行,分為兩部分:

傳輸協議:HTTP1.0和HTTP1.1。

狀態碼:200表示成功;404表示無該頁面。

圖中紅色2表示:應答頭,因鍵值對的形式標識伺服器或者是資料屬性,如:

Server:Apache-Coyote/1.1,伺服器型別。

Content-Length:125,字型長度。

Last-Modified:Wed,21 Sep 2016 15:39:17 GMT,資源的最後修改時間。

圖中紅色3表示:應答體,伺服器返回瀏覽器請求的資源。

    雖然我的瀏覽器也可以訪問HTTP伺服器,並且返回資源,但是與真正的瀏覽器還是有差距的,主要區別如下:

    1、它只需要輸入一個URL,就可以自動完成訊息的組裝併發送給伺服器。

    2、它可以接收資料後,一方面會解析並遮蔽掉對使用者無用的應答行和應答頭,另外它最強大的功能就是可以解析應答體, 並顯示更加生動的頁    面給使用者。

3、不使用瀏覽器,除了通過Socket模擬瀏覽器的方式,還有辦法傳送HTTP請求嘛?

  在個人的程式中,往往是不太方便去呼叫瀏覽器實現HTTP請求,即使可以也存在一個問題,就是瀏覽器返回的應答體,並不能被我們所利用;而通過Socket實現HTTP請求,也會出現一個問題就是它返回的IO流資料中包含了應答行和應該頭,我們要自己去剔除這部分內容,保留應答體,這才是我們所需要的,有沒有更好的方式呢?答案是肯定的。

 3.1 請求方式GET:

1、通過字串,構建一個URL物件。

2、呼叫URL的URLConnection openConnection()方法返回一個URLConnection物件,該物件是是HTTP協議和URL的封裝。

3、通過URLConnection類提供的方式,設定引數或者請求屬性。

設定引數,如:

void setConnectTimeout(int timeOut) 連線超時。

void setReadTimeout(int timeout),讀取資料超時。

void setDoOutput(boolean dooutput),連線伺服器後是否可以向其傳輸資料,如果是需要提交資料,則需要明   確設定為true,因為預設值是false。

一般請求屬性,如:

void setRequsetProperty(String key,String value)

4、呼叫void connect()連線伺服器。

5、呼叫URLConnection類提供的方式,訪問應答頭資訊或者是返回資料。

OutputStream getInputStream(),返回輸入流。

String getHeaderField(String name),返回指定的頭欄位值。

因為應該頭資訊需要經常訪問,所以API中也提供了單獨的方法,比如:

String getContentType(),返回content-type 頭欄位的值。

int getContentLength(),返回content-length 頭欄位的值。

long getDate(),返回date 頭欄位的值。

long getLastModifed,返回last-modified 頭欄位的值。

注意:這裡並沒有明確指定請求方式為GET,因為預設是GET。

程式碼示例:

package com.example.network.http;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class URLConnectionWithGet {

	public static void main(String[] args) throws IOException {
		//1.建立一個字串形式的URL
		String str_url = "http://localhost:8080/myweb/mypage.html";
		//2.通過URL類的建構函式接收一個字串形式的URL,來建立URL一個物件
		URL url = new URL(str_url);
		//3.呼叫openConnection()方法來返回會一個URLConnection物件,它是具體傳輸協議和URL的封裝
		URLConnection conn = url.openConnection();
		//4.通過URLConnection來設定引數和請求屬性,根據實際需要,不設定有預設值。
		conn.setRequestProperty("Content-Type", "text/html");
		//5.呼叫connect()方法建立與伺服器的連線,或者直接呼叫getInputStream()方法,返回輸入流,它可以讀取伺服器的應答體內容,此方法包含connect()的動作,所以可以跳過connect()。
		InputStream in = conn.getInputStream();
		//6.讀取輸入流並列印
		byte[] buf = new byte[1024];
		
		int len = in.read(buf);
		
		System.out.println(new String(buf,0,len));
		
		in.close();

	}

}

3.2 POST方式:與GET方式不同的地方在於:

1、必須要呼叫setDoOutput(true)方法,設定該引數,允許向伺服器輸入資料。

2、必須在connect()或者getInputStream()方法之前呼叫getOutputStream()返回輸出流,並且寫入資料,資料的格式為:name1=value1&name2=value2。

程式碼示例:

客戶端:

package com.example.network.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;

public class URLConnecionWithPost {

	public static void main(String[] args) throws IOException {

				URL url = new URL("http://localhost:8080/myweb/login.jsp");
				
				URLConnection conn = url.openConnection();
				
				conn.setDoOutput(true);	
				OutputStream out = conn.getOutputStream();
				out.write("name=noodles&pass=26".getBytes());

				InputStream in = conn.getInputStream();
				byte[] buf = new byte[1024];	
				int len = in.read(buf);		
				System.out.println(new String(buf,0,len,"utf-8"));
				
				in.close();
				out.close();

	}

}


服務端:

<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<%
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
String pass = request.getParameter("pass");
if(name.equals("noodles")
	&& pass.equals("26"))
{
	out.println("登入成功!");
}
else
{
	out.println("登入失敗!");
}
%>

結果:


注意:這裡也沒有明確的指定以POST方式,但是它預設以POST的方式。

  補充:URLConnection還有一個子類HttpURlConnection,它是特定支援http協議的,它提供了一些額外的便捷方法,如void SetRequestMethod(String method),設定傳送請求的正規化;void disconnect()可以在連線空閒足夠長時間後關閉。具體使用於URLConnection沒有太多差別,一般就是要新增上面所說的兩個方法。

相關推薦

Java Sokect程式設計HTTP請求

1、概述   HTTP是一種協議,全稱超文字傳輸協議,而網頁就屬於超文字(就是為了它服務的),可以支援多媒體等,比如圖片、音訊,豐富了使用者的體驗;它屬於網路模型中應用層的協議,底層基於TCP/I

Java web程式設計基礎理論詳解(計算機網路基礎,HTTP請求的完成過程)

1.計算機網路基礎知識 首先我們需明確通訊系統互聯參考模型: OSI/RM模型與TCP/IP模型:                  OSI/RM模型是一種事實上被TCP/IP模型淘汰的模型,在當今世界上沒有大規模使用。當發生HTTP請求時,傳送方傳送的資料是由最頂

java網路socket程式設計(六)HTTP請求/響應報文

介紹 http報文包含請求報文和響應報文2種報文,他們都包含起始行、首部欄位、主體三部分。其中,請求報文為客戶端向伺服器端請求資源時傳送的http報文位請求包含,而響應報文為從伺服器端發往客戶端的報文

Javahttp請求亂碼問題解決

連接 tco get div gbk readline url prop safari 這周由於項目需要請求一個接口,獲取數據,反復嘗試,請求的數據始終亂碼。這裏簡單的總結一下解決亂碼的幾個方法。 首先,需要註意的是編碼方式的一致,其次對方怎麽編碼,接收方怎麽解碼即可。 先

Java HTTP請求亂碼解決,GZIP 返回值亂碼解決

今天請求一個天氣介面,發現一直亂碼,開始沒注意看請求頭資訊,平時 HTTP  請求無非幾種方法解決亂碼問題。其實只要注意一點就可以了,編碼一致即可,其次對方怎麼編碼,接收方怎麼解碼即可。 HTTP請求亂碼解決方案一 這也是最簡單的方式,主要是用IOUtils工具類。

網路程式設計HTTP中GET與POST請求

1 參考自w3schools給出一個“標準答案” GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊; GET引數通過URL傳遞,POST放在Request body中; GET請求在URL中傳送的引數是有長度限制的,而POST沒有;

四、java專案常用工具類http請求工具類

專案環境: jdk1.8+spring4.3.12 一、問題描述及試用場景: 在專案開發中,經常用呼叫http介面,下面是封裝apache的httpclient工具類。 二、樣例程式碼: package org.egg.utils; import org.ap

Java程式設計HTTP的Post、Get、Put、Delete

Http:在網路中,傳送檔案、資料需要遵循的一種協議。客戶端需要和伺服器端建立聯絡,就需要使用HTTP協議,保證伺服器端可以識別客戶端的請求,並把相應的資源發給客戶端使用。例如,訪問CSDN,在不同電腦的網頁上輸入https://www.csdn.net/即可看到CSDN的網

APP接口自動化測試JAVA+TestNG(三)HTTP接口測試實例

ons ace src 沒有 app 9.png 轉載 image try 前言 前兩篇普及相關基礎知識後,本篇主要對舉例對國家氣象局接口自動化測試進行講解(Get請求及結果斷言),以達到自動化測試入門目的,除了前兩篇的一些了解外,需要有一定的JAVA知識(HTTP

Jmeter源碼Http請求布局樣式修改(三)

Jmeter修改點包括:協議、端口號、域名等 界面: 涉及的類:類:JLabeledTextField.java修改的代碼:Jmeter源碼之Http請求布局樣式修改(三)

angular6http請求攔截器

cat catch ken pre resp error ava pipe export 在前端項目中我們往往需要對每次請求做一些統一的處理,比如請求結果session過期處理,在header頭部加上驗證參數token等等,這個時候就需要用到攔截器。 由於angular中h

學習筆記-JmeterHTTP請求預設值

轉自:https://www.cnblogs.com/ShadowXie/p/6008967.html 一、HTTP Request Defaults的作用:   該元件可以為我們的http請求設定預設的值。假如,我們建立一個測試計劃有很多個請求且都是傳送到相同的server,這時我

java併發程式設計利用CAS保證操作的原子性

import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class Counter { private AtomicInteger at

Java併發程式設計CyclicBarrier

CyclicBarrier可以控制這樣的場景: 對多個執行緒,他們執行自己程式碼(執行run方法)的時間不一樣; 比如有3個執行緒,其run方法執行時間分別為1s, 2s, 3s。如果我們想在三個執行緒都完成自己的任務時執行相應的操作,CyclicBarrier就派上用場了。 寫了一

Java併發程式設計鎖機制LockSupport工具

關於文章涉及到的jdk原始碼,這裡把最新的jdk原始碼分享給大家----->jdk原始碼 前言 在上篇文章《Java併發程式設計之鎖機制之AQS(AbstractQueuedSynchronizer)》中我們瞭解了整個AQS的內部結構,與其獨佔式與共享式獲取同步狀態的實現

Java併發程式設計執行緒生命週期、守護執行緒、優先順序和join、sleep、yield

Java併發程式設計中,其中一個難點是對執行緒生命週期的理解,和多種執行緒控制方法、執行緒溝通方法的靈活運用。這些方法和概念之間彼此聯絡緊密,共同構成了Java併發程式設計基石之一。 Java執行緒的生命週期 Java執行緒類定義了New、Runnable、Running Man、Blocked和Dead

Java併發程式設計執行緒安全、執行緒通訊

Java多執行緒開發中最重要的一點就是執行緒安全的實現了。所謂Java執行緒安全,可以簡單理解為當多個執行緒訪問同一個共享資源時產生的資料不一致問題。為此,Java提供了一系列方法來解決執行緒安全問題。 synchronized synchronized用於同步多執行緒對共享資源的訪問,在實現中分為同步程

Java併發程式設計ThreadGroup

ThreadGroup是Java提供的一種對執行緒進行分組管理的手段,可以對所有執行緒以組為單位進行操作,如設定優先順序、守護執行緒等。 執行緒組也有父子的概念,如下圖: 執行緒組的建立 1 public class ThreadGroupCreator { 2 3 publi

Java併發程式設計Exchanger

概述   用於執行緒間資料的交換。它提供一個同步點,在這個同步點,兩個執行緒可以交換彼此的資料。這兩個執行緒通過exchange方法交換資料,如果第一個執行緒先執行exchange()方法,它會一直等待第二個執行緒也執行exchange方法,當兩個執行緒都到達同步點時,這兩個執行緒就可以交換資料

java併發程式設計使用 CountDownLatch 控制多個執行緒執行順序

有時候會有這樣的需求,多個執行緒同時工作,然後其中幾個可以隨意併發執行,但有一個執行緒需要等其他執行緒工作結束後,才能開始。舉個例子,開啟多個執行緒分塊下載一個大檔案,每個執行緒只下載固定的一截,最後由另外一個執行緒來拼接所有的分段,那麼這時候我們可以考慮使用CountDownLatch來控制併發。