網頁瀏覽器為了獲取服務器上關於該網站的HTML文件,透過HTTP協議向服務器發起請求,不過我們在網頁中是使用可以讓人看得懂的域名地址,因此網頁瀏覽器會調用socket庫中關於獲取DNS的函數,並把返回的IP地址與HTTP請求一併交給傳輸層,接下來作業系統會使用socket函數創建socket(1)、利用IP地址與Port(端口號)與服務器建立連線、收發封包、最後斷開連結
HTTP是甚麼?其實HTTP是超文本傳輸協定的縮寫,那麼大家一定好奇它究竟是什麼意思,其實可以這樣理解:
傳輸
協定
其實HTTP協議的核心概念就是,瀏覽器向指定服務器發出特定類型的需求,服務器再按照需求回傳資料給瀏覽器。其實說到底就是針對誰做甚麼操作,誰指的是URI,而操作指的就是方法
上圖示常見的URL格式,當我們在搜尋欄輸入一連串http:// 開頭字串時,這些網址準確的說就是URL(統一資源定位符),他不一定是要用http:// 作為開頭,也可以是ftp:// ,這些都依照使用的應用程式而定
不過有人可能會好奇www. 開頭的是否是另一種網路協定呢?其實不是,www就是World Wide Web的縮寫,是一種網頁命名方式,他是早期用來開發網頁以及HTML的編輯器名,算是一種歷史傳承吧
透過上圖可以發現URL其實就是網頁服務器中關於特定資料的文件路徑,透過取得該文件,我們就可以再瀏覽器上顯示出該網站的資訊了,不過網路的傳輸是使用所謂的IP地址,而非域名地址(2),這部份我們會在DNS部分介紹
我們緊接著把上圖拆成5個部份來介紹,分別是:
但是可能有人會問,我在網址欄輸入URL時只有打上 www.xxx.com 阿,並沒有在字串尾部詳細加上資源路徑地址,這個URL是很精簡沒錯,那麼到底服務器能不能找到確切資料?
從這一部份可以帶出網頁瀏覽器的第一份任務→對URL進行解析,判斷對誰進行操作
我們先說說URI的定義,URI就是在某一規則下能把一個資源獨一無二的表示出來,我們順著這個思路來舉個例子
假如我們透過學生證號來查詢該名學生,這個學號是獨一無二的,意思是在這個校園內不可能會有第二個擁有相同學號的學生,因此假若我們確切得知該生的學號那就一定可以確定是他
我們把焦點回到服務器上,例如文件名都有特定名稱: xxx.html或是給該文件設定特定編號html: xxx
同理我們使用絕對位置來尋找這名學生,透過電腦中遺留的線索發現他是哈哈大學電機系的學生,目前住在第二宿舍的301房2床,用這種絕對路徑的方式也可以將該生找出來,且是獨一無二的
這種表達方式我們並不陌生,例如 www.xxx.com.tw/dir/file/index.html ,就是列出該文件的絕對路徑
相反的,我們若是用鬆散的資料來查找,例如王曉明同學,誰知道這個學校有幾個王曉明?,電機系王同學會打排球?假如整個排球隊都姓王勒?(別說不可能),這種沒辦法信誓旦旦地指出對方的方法就不屬於URI
說到底URL其實也是URI的其中一種,它只是用路徑定位的方式來表達唯一的文件,因此我們可以下一個結論: URL是URI的一個子集合
而在HTTP的發送請求中我們一般是將URL稱作URI,不過我個人更偏好URL,因為這樣從輸入網址到解析URL,再到HTTP消息封裝會更加直觀好懂,除非真的訪問一個有唯一編號名稱的/dir/123456789.html文件
所謂的method(方法)就是對服務器下達特殊的指令,決定對服務器進行什麼樣的操作,我們稱之為方法,服務器接收客戶端請求後會按照方法來完成工作,以下介紹常見的幾種方法
常見方法 | 含意 | 例子 |
---|---|---|
GET | 向服務器請求某個已經被URI定位的文件,目的是得到服務器返回響應 | GET /dir/index.html HOST: www.xxx.com.tw |
POST | 客戶端向服務器發送數據消息,一般來說在填表格或留言會用得上 | POST /submit.cgi HOST: www.xxx.com.twContent-Length: 1600(4) |
PUT | 更新服務器上被URI指定的文件,若是沒有該文件則新創建一個 | PUT /file.html HOST: www.xxx.com.twContent-Type: text/htmlContent-Length: 1600 |
HEAD | 與GET方法類似,但只要求返回頭部消息,多用在檢查文件狀態 | HEAD /dir/index.html HOST: www.xxx.com.tw |
DELETE | 刪除服務器上被URI指定的文件 | DELETE /dir/index.html HOST: www.xxx.com.tw |
OPTIONS | 詢問URI指定的資源支持那些方法 | OPTIONS* HOST: www.xxx.com.tw |
TRACE | 服務器會返回它收到的請求。其目的是為了比對請求數據再傳輸過程中是否被竄改,Max-Foward字段在經過服務器時會減去1,直到變成0時則不再轉發消息 | TRACE /HOST: www.xxx.com.twMax-Fowards: 7 |
CONNECT | 向代理服務器發起請求,要求建立TCP的Socket通道 | CONNECT proxy.xxx.com:8080 HOST: proxy.xxx.com |
其實在瀏覽器上的不同操作會觸發不同的方法,例如輸入網址與發送表單使用的方法是不一樣的。以下我們就大致介紹請求中各個區段的涵義
如上一小節所描述,就是對服務器請求的種類,比較要注意的是該方法是否需要使用到消息主體
瀏覽器使用的HTTP當前版本,常見如HTTP/1.1
儘管方法已經告知服務器請求內容,但有些狀況往往需要更具體的請求,例如日期、檔案要多新、檔案的長度、檔案的壓縮類型等等,這些就是首部字段的功用,作為方法的補充,再請求中常會見到3種首部字段,分別是請求首部字段、通用首部字段、實體首部字段(5)
為請求方法附加更多詳細內容的字段就是請求首部字,例如接受的文件類型、語言、長度等等
請求首部字段 | 含意 |
---|---|
Accept | 可接受的文件類型 |
Accept-Encoding | 可接受的編碼 |
Accept-Language | 可接受的語言 |
If-Modified-Since | 獲取資源的更新狀態 |
If-Range | 若資源未更新時發送具有範圍的請求 |
Range | 若資源未更新則依照這個範圍的byte作為請求 |
通用首部字段就是請求與響應都會用到的首部字段,例如日期、選用連線狀態等等
通用首部字段 | 含意 |
---|---|
Cache-Control | 控制服務器緩存 |
Connection | 使代理刪除首部字段與持久連接控制 |
Date | 創建封包的時間消息 |
Pragma | 通常用在不接受緩存消息上 |
Transfer-Encoding | 指定封包編碼方式 |
Upgrade | 檢查是否要更高版本的協定可用 |
補充請求與響應的消息主體附加訊息
實體首部字段 | 含意 |
---|---|
Content-Encoding | 消息主體的編碼方式 |
Content-Language | 消息主體使用的語言 |
Content-Length | 消息主體的大小 |
Content-Range | 消息主體的資料範圍 |
Last-Modified | 資源的最後修改時間 |
所有使用者需要的消息以及欲收發的文件都包含在這裡
消息主體部分就會依照方法來決定是否要啟用,例如PUT與POST方法就需要加入一個文件到消息主體中,而GET僅需要方法、版本、首部字段就可以進行傳輸了
服務器完整收到客戶端發送來的請求後會依照請求方法來處理資料,並將文件處理的結果以及客戶端所需要的資料連同首部字段返回給客戶端,該資料封包就稱為HTTP響應,其實HTTP響應與HTTP請求只差在狀態行與方法,剩下的首部字段與消息主體邏輯是雷同的
同請求部分,只是響應的版本資訊放在第一個
狀態碼就是服務器處理請求時的狀態描述,例如我們常見的404 not found就是服務器無法找到請求的資料位置的狀態回報,如上圖所示,我們會大概介紹一下常見的幾種狀態碼以及他們的含意
1xx為一種過渡階段,表示請求正在處理中,不過這個狀態碼比較少見
2xx表示客戶端請求已經被指定服務器接收,並且正確的處理,這是我們最想看見的結果,常見的狀態碼有:
狀態碼 | 含意 | 備註 |
---|---|---|
200 OK | 表示請求被正確處理,服務器依照需求返回客戶端需要的數據 | -- |
204 No Content | 請求被處理成功,但返回的響應不包含消息主體 | 一般運用在客戶端發送請求但不需要返回響應時 |
206 Partial Content | 響應返回成功,但返回的消息主體只是整個消息主體的其中一部分 | 常見於HTTP的分批下載與斷點續傳 |
目標資源位置發生變動,需要客戶端進行重定向處理
狀態碼 | 含意 | 備註 |
---|---|---|
301 Moved Permanently | 訪問的該資源已經永久移到別處,需要使用新的URI訪問 | 響應會附加Location首字段標示新的URI |
302 Found | 資源找到了,但暫時需要用另一個URI訪問 | 響應會附加Location首字段標示新的URI |
304 Not Modified | 服務器允許請求訪問資源,但資源並不符合請求的附加條件 | 其實該條狀態碼與重定向無關,另外響應不包含消息主體部分 |
客戶端在訪問服務器時發生錯誤或缺乏權限
狀態碼 | 含意 | 備註 |
---|---|---|
400 Bad Request | 客戶端發送請求格式錯誤,服務器無法理解 | -- |
403 Forbidden | 客戶端沒有權限訪問該筆資源 | -- |
404 Not Found | 服務器不存在該資源 | -- |
服務器在處理請求的過程中發生錯誤,返回響應讓客戶端知道
狀態碼 | 含意 | 備註 |
---|---|---|
500 Internal Server Error | 服務器在處理請求時發生錯誤 | 也有可能是Web發生bug導致 |
501 Not Implemented | 服務器尚不支援該請求的功能 | -- |
503 Service Unavailable | 服務器忙碌中,暫時無法處理客戶端請求 | 服務器會返回帶有Retry-After首部字段的響應,告訴客戶端等等再發送一次 |
服務器響應中的首字段與請求大致相同,主要差別在響應首部字段。不過這並不並代表同一個請求與響應的通用首部字段與實體首部字段會完全相同,還是要依據消息狀態類型來判斷,只是說兩邊都有可能使用到相同的共用首字段,例如Date字段
響應首部字段多用於補充資料消息以及告訴客戶端收到響應該做什麼
響應首部字段 | 含意 |
---|---|
Accept-Ranges | 是否可以接受範圍請求 |
Age | 告訴客戶端服務器在多久之前創立響應 |
Location | 告知客戶端重定向URI位置 |
Retry-After | 告知客戶端多久以後再發起請求 |
響應的消息主體就是服務器依照客戶端請求返回的文件或資料,消息主體的內容會以二進制方式表示
最後我們可以利用這張簡單的示意圖來回想客戶端是如何利用HTTP協定與服務器溝通,從而獲得某個網站的頁面(該頁面有一個名為abc的圖檔)
(1):其實我們可以先把socket想像成兩個應用程式之間的連線狀態,相當於通信的"通行證",卻好雙方狀態後就可以開始傳輸了
(2):使用域名是方便使用者記住以及輸入網址,畢竟 www.google.com 比一連串數字好記多了吧
(3):/代表資料夾的跟目錄,它是目錄層級的最頂層,一般沒有名字。你可以在終端機中cd /看看會發生什麼事
(4):關於資料長度的首部字段,常見的首部字段可以查閱HTTP介紹文件
(5):其實我們不需要背這些字段的意思是甚麼,只要知道常用的幾個就可以了,其他不懂的字段名用到時再去查閱就可以了,要注意學習網路重要的是這些機制的交互行為、為什麼這麼做、為了解決什麼問題