HTTP (Hypertext Transfer Protocol) 是一種應用層協定,它是全球資訊網 (World Wide Web) 的基石。簡單來說,它就像一套溝通的語言,讓網頁瀏覽器(例如 Chrome、Firefox)和網路伺服器之間能夠互相傳送資訊。
想像一下,你想要去餐廳點餐。HTTP 協定就像是服務生,你(瀏覽器)告訴服務生你想點什麼菜(發送 請求),服務生把你的單子送給廚房(伺服器),廚房做好菜之後(處理請求),服務生再把菜送回來給你(發送 回應)。
HTTP 協定的運作模式是基於「請求-回應」的架構,整個過程可以分解為以下步驟:
建立連線:首先,瀏覽器會與伺服器建立一個 TCP 連線。
發送請求 (Request):瀏覽器向伺服器發送一個 HTTP 請求,這個請求通常包含:
請求方法 (Method):告訴伺服器想做什麼,常見的方法有:
GET:用來取得資料,例如載入網頁、圖片。
POST:用來提交資料,例如填寫表單、註冊帳號。
URL (Uniform Resource Locator):指定想存取的資源位址,例如 https://www.google.com/。
請求標頭 (Headers):提供關於請求的額外資訊,例如瀏覽器類型、語言偏好。
請求主體 (Body):如果請求需要提交資料,資料會放在這裡(例如 POST 方法)。
伺服器處理請求:伺服器收到請求後,會根據請求的內容來處理,例如從資料庫中查詢資料或執行特定操作。
發送回應 (Response):伺服器處理完畢後,會回傳一個 HTTP 回應給瀏覽器,這個回應包含:
狀態碼 (Status Code):一個三位數的數字,用來告訴瀏覽器這次請求的結果。
200 OK:表示成功。
404 Not Found:表示找不到請求的資源。
500 Internal Server Error:表示伺服器發生錯誤。
回應標頭 (Headers):提供關於回應的額外資訊,例如內容類型、伺服器資訊。
回應主體 (Body):實際回傳的內容,例如網頁的 HTML 程式碼、圖片檔案等。
關閉連線:通常在傳輸完成後,連線會被關閉。
無狀態 (Stateless):這是 HTTP 最重要的特性之一。每個請求都是獨立的,伺服器不會「記得」之前的請求。這就像服務生每次都把你當成第一次來的客人,如果你需要他記得你,就必須在每個請求中都附上證明(例如使用 Cookie 或 Session)。
靈活性:HTTP 傳輸的內容不限於文字,可以是圖片、影片、音訊等多媒體檔案。
可擴充:HTTP 協定可以透過新增標頭來擴充功能。
一個 HTTP 請求訊息是從客戶端(通常是瀏覽器)發送給伺服器的,用於請求資源或提交資料。
HTTP/1.1 協定中的訊息主要分為兩種:請求 (Request) 和 回應 (Response)。它們的格式雖然有些不同,但都遵循相同的基本結構:
起始行 (Start Line):定義了訊息的目的。
標頭 (Headers):提供關於訊息的額外資訊。
空行:用來區隔標頭和訊息主體,這行非常重要。
訊息主體 (Message Body):包含實際傳輸的資料。
在 HTTP 協定中,GET 是一種最常用且最基礎的請求方法,主要用來向伺服器請求或取得資源,例如網頁、圖片、CSS 檔案等。
與 POST 請求最大的不同在於,GET 請求不會將資料放在訊息主體中,而是將資料附加在 URL 的查詢字串 (Query String) 裡。因此,GET 請求的訊息格式通常沒有主體。
格式結構 (包含換行符號):
[請求行]\r\n
[請求標頭]\r\n
[空行]\r\n
\r\n 代表 回車 (CR) 和 換行 (LF) 的組合,這是 HTTP 協定中定義的標準換行符號。
格式說明:
請求行 (Request Line):
方法 (Method):固定為 GET。
URL (URI):指定要取得的資源路徑。如果需要傳遞資料,會以 ? 符號開始,後面接續以 & 符號分隔的查詢字串。
協定版本 (Protocol Version):通常是 HTTP/1.1。
請求標頭 (Request Headers):
Host:指定伺服器的網域名稱。
User-Agent:提供客戶端的軟體資訊,例如瀏覽器類型和版本。
Accept:指定客戶端可以接收的回應內容類型(例如 text/html、application/json)。
空行 (\r\n):
這是 HTTP 協定的硬性規定,用來分隔請求標頭和訊息主體。
在 GET 請求中,因為沒有主體,所以空行後是空的。
請求主體 (Request Body):
GET 請求沒有請求主體。
下面是一個使用查詢字串傳遞參數的 GET 請求範例:(包含換行符號):
GET /search?q=http+protocol&lang=en HTTP/1.1\r\n
Host: www.google.com\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)\r\n
Accept-Language: en-US,en;q=0.9\r\n
\r\n
在請求標頭後,一個單獨的 \r\n 表示空行,用來區隔標頭和訊息主體。在 GET 請求中,通常沒有主體,所以空行後面是空的。
解析這個範例:
請求行:GET /search?q=http+protocol&lang=en HTTP/1.1
/search 是資源路徑。
?q=http+protocol&lang=en 是查詢字串,其中 q 和 lang 是參數名稱,http+protocol 和 en 是對應的值。
標頭:
Host: www.google.com:目標伺服器。
User-Agent:瀏覽器資訊。
Accept-Language:偏好的語言。
空行:一個單獨的 \r\n。
GET 請求的特性與限制
公開性:由於資料包含在 URL 中,它們會暴露在瀏覽器的歷史記錄、伺服器日誌和書籤中,不適合傳輸敏感資訊(如密碼或個人資料)。
長度限制:URL 的長度通常有限制(約 2048 個字元),這也限制了 GET 請求能傳輸的資料量。
冪等性 (Idempotent):GET 請求是冪等的,意味著多次發送相同的請求,伺服器狀態不會因此改變。這使得 GET 請求可以被安全地重複發送或被瀏覽器快取。
GET /hello.htm HTTP/1.1\r\n
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n
Host: www.tutorialspoint.com\r\n
Accept-Language: en-us\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: Keep-Alive\r\n
\r\n
GET 請求主要是用來取得資料,所以它的請求主體通常是空的。
而 POST 請求則是用來提交資料,例如提交一個表單、上傳一個檔案,或是傳送 JSON 格式的資料到伺服器。因此,它的訊息主體中會包含實際的資料內容。
格式結構 (包含換行符號):
[請求行]\r\n
[請求標頭]\r\n
[空行]\r\n
[請求主體]
\r\n 代表 回車 (CR) 和 換行 (LF) 的組合,這是 HTTP 協定中定義的標準換行符號。
格式說明:
請求行 (Request Line):
方法 (Method):固定為 POST。
URL (URI):指定要接收資料的伺服器資源路徑。
協定版本 (Protocol Version):通常是 HTTP/1.1。
請求標頭 (Request Headers):
Host:指定伺服器的網域名稱。
Content-Type:這個標頭對 POST 請求至關重要,它用來告訴伺服器請求主體中的資料是什麼類型。常見的類型有:
application/x-www-form-urlencoded:用於提交標準的 HTML 表單資料,資料會被編碼為 URL-encoded 格式,類似於 name=John&age=30。
multipart/form-data:用於提交包含檔案的表單(例如圖片上傳)。
application/json:用於傳輸 JSON 格式的資料,這在現代的 RESTful API 中非常常見。
Content-Length:這個標頭用來告訴伺服器訊息主體的長度(以位元組為單位),這有助於伺服器正確地讀取完整的資料。
空行 (\r\n):
標頭結束後,必須有一個空行來分隔標頭和訊息主體。這是 HTTP 協定的硬性規定。
請求主體 (Request Body):
包含實際要傳送的資料。這部分的內容會根據 Content-Type 標頭所指定的格式來編寫。
POST 請求範例 (包含換行符號):
下面是一個使用 application/json 格式提交資料的 POST 請求範例:
POST /api/users HTTP/1.1\r\n
Host: example.com\r\n
Content-Type: application/json\r\n
Content-Length: 42\r\n
\r\n
{"name": "John Doe", "email": "john.doe@example.com"}
解析這個範例:
請求行:POST /api/users HTTP/1.1,表示要將資料提交到 /api/users 這個路徑。
標頭:
Host: example.com:目標伺服器。
Content-Type: application/json:告訴伺服器訊息主體是 JSON 格式。
Content-Length: 42:告訴伺服器訊息主體的長度是 42 個位元組。
空行:一個單獨的 \r\n。
請求主體:
{"name": "John Doe", "email": "john.doe@example.com"},這就是實際傳輸的 JSON 資料。
總結來說,POST 請求的核心在於它的請求主體,以及用來描述這個主體內容的 Content-Type 和 Content-Length 標頭。
POST /cgi-bin/process.cgi HTTP/1.1\r\n
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n
Host: www.tutorialspoint.com\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: length\r\n
Accept-Language: en-us\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: Keep-Alive\r\n
\r\n
licenseID=string&content=string&/paramsXML=string
POST /?id=1 HTTP/1.1\r\n
Host: echo.paw.cloud\r\n
Content-Type: application/json; charset=utf-8\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0\r\n
Connection: close\r\n
Content-Length: 136\r\n
\r\n
{
"status": "ok",
"extended": true,
"results": [
{"value": 0, "type": "int64"},
{"value": 1.0e+3, "type": "decimal"}
]
}
POST /cgi-bin/process.cgi HTTP/1.1\r\n
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n
Host: www.tutorialspoint.com\r\n
Content-Type: text/xml; charset=utf-8\r\n
Content-Length: 125\r\n
Accept-Language: en-us\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: Keep-Alive\r\n
\r\n
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://clearforest.com/">string</string>
當伺服器收到一個 HTTP 請求並處理完畢後,會回傳一個 回應 (Response) 訊息給客戶端(瀏覽器)。這個回應訊息是請求-回應週期的最後一步,包含了伺服器對請求的處理結果以及客戶端所請求的資源。
一個 HTTP 回應訊息的結構與請求訊息相似,都由三大部分組成:狀態行、回應標頭,以及可選的回應主體。
格式結構 (包含換行符號):
[狀態行]\r\n
[回應標頭]\r\n
[空行]\r\n
[回應主體]
格式說明:
狀態行 (Status Line):
這是回應訊息的第一行,包含了三個部分,用空格分隔。
協定版本 (Protocol Version):表示伺服器使用的 HTTP 版本,例如 HTTP/1.1。
狀態碼 (Status Code):一個三位數的數字,用來告訴客戶端這次請求的結果。
1xx (資訊):表示請求已接收,繼續處理。
2xx (成功):表示請求已成功接收、理解、並接受。200 OK 是最常見的成功狀態碼。
3xx (重新導向):表示需要採取進一步的行動來完成請求。例如 301 Moved Permanently。
4xx (客戶端錯誤):表示請求有語法錯誤或無法實現。例如 404 Not Found 和 403 Forbidden。
5xx (伺服器錯誤):表示伺服器在處理有效請求時失敗。例如 500 Internal Server Error。
狀態訊息 (Reason Phrase):對狀態碼的簡短文字描述,例如 OK、Not Found。
回應標頭 (Response Headers):
標頭提供了關於回應的額外資訊,每個標頭都是以 鍵: 值 的形式呈現。
常見的標頭有:
Content-Type:非常重要,告訴客戶端回應主體的內容類型,例如 text/html、application/json、image/jpeg 等。
Content-Length:回應主體的位元組長度,讓客戶端知道何時讀取完畢。
Server:伺服器軟體資訊,例如 Apache 或 nginx。
Cache-Control:控制客戶端或中介伺服器如何快取回應內容。
Set-Cookie:用來在客戶端設定 Cookie。
空行 (\r\n):
這是分隔標頭和訊息主體的硬性規定。
回應主體 (Response Body):
包含了伺服器回傳的實際內容。這個內容可以是 HTML 網頁程式碼、JSON 資料、圖片檔案、影片檔案等。
回應訊息範例:
下面是一個針對 GET /index.html 請求的成功回應範例:
HTTP/1.1 200 OK\r\n
Content-Type: text/html; charset=UTF-8\r\n
Content-Length: 154\r\n
Date: Mon, 22 Jan 2024 10:00:00 GMT\r\n
\r\n
<!DOCTYPE html>\r\n
<html>\r\n
<head>\r\n
<title>Hello World</title>\r\n
</head>\r\n
<body>\r\n
<h1>Welcome to My Website</h1>\r\n
</body>\r\n
</html>
解析這個範例:
狀態行:HTTP/1.1 200 OK,表示請求成功。
標頭:
Content-Type: text/html; charset=UTF-8:告知瀏覽器回傳的是一個 HTML 網頁,並且編碼為 UTF-8。
Content-Length: 154:告知瀏覽器主體內容長度為 154 個位元組。
Date:顯示回應發送的時間。
空行:一個單獨的 \r\n。
回應主體:<!DOCTYPE html>...,這是客戶端請求的 HTML 網頁內容。
錯誤回應範例 (404 Not Found)
當請求的資源不存在時,伺服器會回傳一個 404 Not Found 的錯誤回應:
HTTP/1.1 404 Not Found\r\n
Content-Type: text/html\r\n
Content-Length: 125\r\n
Date: Mon, 22 Jan 2024 10:05:00 GMT\r\n
\r\n
<!DOCTYPE html>\r\n
<html>\r\n
<head><title>404 Not Found</title></head>\r\n
<body>\r\n
<h1>Page Not Found</h1>\r\n
</body>\r\n
</html>
在這個範例中,狀態碼從 200 變成了 404,而回應主體則可能包含一個友善的錯誤頁面,而不是客戶端原先請求的資源。
HTTP/1.1 200 OK\r\n
Date: Mon, 27 Jul 2009 12:28:53 GMT\r\n
Server: Apache/2.2.14 (Win32)\r\n
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT\r\n
Content-Length: 88\r\n
Content-Type: text/html\r\n
Connection: Closed\r\n
\r\n
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
HTTP/1.1 404 Not Found\r\n
Date: Sun, 18 Oct 2012 10:36:20 GMT\r\n
Server: Apache/2.2.14 (Win32)\r\n
Content-Length: 230\r\n
Connection: Closed\r\n
Content-Type: text/html; charset=iso-8859-1\r\n
\r\n
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<h1>Not Found</h1>
<p>The requested URL /t.html was not found on this server.</p>
</body>
</html>
HTTP/1.1 400 Bad Request\r\n
Date: Sun, 18 Oct 2012 10:36:20 GMT\r\n
Server: Apache/2.2.14 (Win32)\r\n
Content-Length: 230\r\n
Content-Type: text/html; charset=iso-8859-1\r\n
Connection: Closed\r\n
\r\n
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>400 Bad Request</title>
</head>
<body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.</p>
<p>The request line contained invalid characters following the protocol string.</p>
</body>
</html>