HTTP請求頭與請求體詳解

小云云
發布: 2023-03-22 16:02:01
原創
6807 人瀏覽過

本文主要和大家分享HTTP請求頭與請求體詳解,對於HTTP的學習主要包含HTTP 基礎、HTTP 請求頭與請求體、HTTP 回應頭與狀態碼、HTTP 快取這四個部分,而對於HTTP相關的擴展與引申,我們也需要了解HTTPS 理解與實踐 、HTTP/2 基礎、WebSocket 基礎這些部分。本部分知識點同時也歸納於筆者的我的校招準備之路:從Web前端到服務端應用架構這篇綜述。

 HTTP Request

HTTP 的請求訊息分為三個部分請求行、請求頭和請求體,格式如圖:

一個典型的請求訊息標頭域,如下所示:

  POST/GET http://download.microtool.de:80/somedata.exe  
   Host: download.microtool.de   Accept:*/*   Pragma: no-cache  
    Cache-Control: no-cache   Referer: http://download.microtool.de/ 
      User-Agent:Mozilla/4.04[en](Win95;I;Nav)   Range:bytes=554554-
登入後複製

Request Line:請求行

#請求行(Request Line)分為三個部分:請求方法、請求位址和協定及版本,以CRLF(rn)結束。
HTTP/1.1 定義的請求方法有8種:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常的兩種GET和POST,如果是RESTful介面的話一般會用到GET、 POST、DELETE、PUT。

Request Methods

注意,只有POST、PUT以及PATCH這三個動詞時會包含請求體,而GET、HEAD、DELETE、CONNECT、TRACE、OPTIONS這幾個動詞時不包含請求體。

Header:請求頭

##範例Accept指定客戶端能夠接收的內容類型Accept: text/plain, text/html,application/json #Accept-Charset瀏覽器可以接受的字元編碼集。 Accept-Charset: iso-8859-5#Accept-Encoding指定瀏覽器可以支援的web伺服器傳回內容壓縮編碼類型。 Accept-Encoding: compress, gzip#Accept-Language瀏覽器可接受的語言Accept-Language: en,zhAccept-Ranges可以請求網頁實體的一個或多個子範圍欄位Accept-Ranges: bytesAuthorizationHTTP授權的授權憑證Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==Cache-Control指定要求和回應遵循的快取機制Cache-Control: no-cacheConnection#CookieIf-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMTIf-None-Match如果內容未改變回傳304程式碼,參數為伺服器先前發送的Etag,與伺服器回應的Etag比較判斷是否改變If-None-Match: “737060cd8c284d8af7ad3082f209582d”#If-Range##If-Range
Header解釋
##表示是否需要持久連線。 (HTTP 1.1預設為持久連接)Connection: close
HTTP請求發送時,會把保存在該請求網域下的所有cookie值一起傳送給web伺服器。Cookie: $Version=1; Skin=new;
#Content-Length請求的內容長度Content- Length: 348
Content-Type要求的與實體對應的MIME資訊Content-Type: application/x-www-form- urlencoded
Date請求發送的日期和時間Date: Tue, 15 Nov 2010 08:12:31 GMT
#Expect要求的特定的伺服器行為Expect: 100-continue
From#發出請求的使用者的EmailFrom: user@email.com
#Host指定要求的伺服器的網域名稱和連接埠號碼 Host: www.zcmhi.com
If-Match只有請求內容與實體相符才有效If-Match: 「737060cd8c284d8af7ad3082f209582d」
If-Modified-Since#如果要求的部分在指定時間之後被修改則要求成功,未被修改則傳回304碼
###如果實體未改變,伺服器發送客戶端遺失的部分,否則發送整個實體。參數也為EtagIf-Range: “737060cd8c284d8af7ad3082f209582d”
#If-Unmodified-Since#只在指定時間之後未被修改才要求成功If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
Max-Forwards限制訊息透過代理程式和網關傳送的時間Max-Forwards: 10
#Pragma用來包含實作特定的指令#Pragma : no-cache
Proxy-Authorization#連接到代理程式的授權憑證Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
#Range只要求實體的一部分,指定範圍Range: bytes=500-999
#################################################################################################n ####先前網頁的位址,目前請求網頁緊接著,即來路######Referer: http://www.zcmhi.com/archives...######## ####TE######客戶端願意接受的傳輸編碼,並通知伺服器接受接受尾加頭訊息######TE: trailers,deflate;q=0.5####### #####Upgrade######向伺服器指定某種傳輸協定以便伺服器進行轉換(如果支援)######Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 ############User-Agent######User-Agent的內容包含發出要求的使用者資訊######User-Agent: Mozilla/5.0 (Linux; X11) ############Via######通知中間網關或代理伺服器位址,通訊協定######Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)# ###########Warning######關於訊息實體的警告訊息######Warn: 199 Miscellaneous warning############

Request Body:请求体

Types

根据应用场景的不同,HTTP请求的请求体有三种不同的形式。

任意类型

移动开发者常见的,请求体是任意类型,服务器不会解析请求体,请求体的处理需要自己解析,如 POST JSON时候就是这类。

application/json

application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。

JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。记得我几年前做一个项目时,需要提交的数据层次非常深,我就是把数据 JSON 序列化之后来提交的。不过当时我是把 JSON 字符串作为 val,仍然放在键值对里,以 x-www-form-urlencoded 方式提交。

Google 的 AngularJS 中的 Ajax 功能,默认就是提交 JSON 字符串。例如下面这段代码:

JSvar data = {'title':'test', 'sub' : [1,2,3]};$http.post(url, data).success(function(result) {
    ...
});
登入後複製

最终发送的请求是:

BASHPOST http://www.example.com HTTP/1.1 Content-Type: application/json;charset=utf-8{"title":"test","sub":[1,2,3]}
登入後複製

这种方案,可以方便的提交复杂的结构化数据,特别适合 RESTful 的接口。各大抓包工具如 Chrome 自带的开发者工具、Firebug、Fiddler,都会以树形结构展示 JSON 数据,非常友好。但也有些服务端语言还没有支持这种方式,例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候,需要自己动手处理下:在请求头中 Content-Type 为 application/json 时,从 php://input 里获得原始输入流,再 json_decode 成对象。一些 php 框架已经开始这么做了。

当然 AngularJS 也可以配置为使用 x-www-form-urlencoded 方式提交数据。如有需要,可以参考这篇文章。

text/xml

我的博客之前提到过 XML-RPC(XML Remote Procedure Call)。它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。典型的 XML-RPC 请求是这样的:


HTMLPOST http://www.example.com HTTP/1.1 
Content-Type: text/xml<?xml version="1.0"?><methodCall>
    <methodName>examples.getStateName</methodName>
    <params>
        <param>
            <value><i4>41</i4></value>
        </param>
    </params></methodCall>
登入後複製

XML-RPC 协议简单、功能够用,各种语言的实现都有。它的使用也很广泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服务等等。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。不过,我个人觉得 XML 结构还是过于臃肿,一般场景用 JSON 会更灵活方便。

Query String:application/x-www-form-urlencoded

這算是最常見的 POST 提交資料的方式了。瀏覽器的原生

表單,如果不設定 enctype 屬性,那麼最終就會以 application/x-www-form-urlencoded 方式提交資料。請求類似下面這樣(無關的請求頭在本文中都省略掉了):

POST http://www.example.com HTTP/1.1

Content-Type : application/x-www-form-urlencoded;charset=utf-8
title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

#首先,Content-Type 被指定為application/x-www-form-urlencoded;這裡的格式要求就是URL中Query String的格式要求:多個鍵值對之間用&連接,鍵與值之前用=連接,且只能用ASCII字符,非ASCII字符需使用UrlEncode編碼。大部分服務端語言都對這種方式有很好的支援。例如 PHP 中,$_POST['title'] 可以取得到 title 的值,$_POST['sub'] 可以得到 sub 陣列。

檔案分割

第三種請求體的請求體被分成為多個部分,檔案上傳時會被使用,這種格式最先應該是被用於郵件傳輸中,每個欄位/檔案都被boundary(Content-Type中指定)分成單獨的段,每段以-- 加boundary開頭,然後是該段的描述頭,描述頭之後空一行接內容,請求結束的標制為boundary後面加--,結構見下圖:

#區分是否被當成文件的關鍵是Content-Disposition是否包含filename,因為文件有不同的類型,所以也要使用Content-Type指示文件的類型,如果不知道是什麼類型取值可以為application/octet-stream表示該文件是二進位文件,如果不是文件則Content-Type可以省略。
我們使用表單上傳檔案時,必須讓 表單的 enctyped 等於 multipart/form-data。直接來看一個請求範例:

BASHPOST http://www.example.com HTTP/1.1Content-Type:multipart/form-data; 
boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: 
form-data; name="text"title------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name="file";
 filename="chrome.png"Content-Type: image/pngPNG ... content of chrome.png ...------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
登入後複製

这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。关于 multipart/form-data 的详细定义,请前往 rfc1867 查看。

这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 表单也只支持这两种方式(通过 元素的enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

Encoding:编码

网页中的表单使用POST方法提交时,数据内容的类型是 application/x-www-form-urlencoded,这种类型会:

  1.字符"a"-"z","A"-"Z","0"-"9",".","-","*",和"_" 都不会被编码;

  2.將空格轉換為加號(+)

  3.將非文字內容轉換成"%xy"的形式,xy是兩位數16進位的數值;

  4.在每個name=value 對之間放置& 符號。

web設計者面臨的眾多難題之一便是怎樣處理不同作業系統間的差異性。這些差異效能會造成URL方面的問題:例如,有些作業系統允許檔案名稱中含有空格符,有些又不允許。大多數作業系統不會認為檔案名稱含有符號「#」會有什麼特殊意義;但是在一個URL中,符號「#」表示該檔案名稱已經結束,後面會緊跟著一個fragment(部分)識別碼。其他的特殊字符,非字母數字字符集,它們在URL或另一個操作系統上都有其特殊的含義,表述著相似的問題。為了解決這些問題,我們在URL中使用的字元就必須是一個ASCII字元集的固定字集中的元素,具體如下:

  1.大寫字母A-Z

#  2.小寫字母a-z

  3.數字0-9

  4.標點符- _ . ! ~ * ' (和,)

#  諸如字元: / & ? @ # $ + = 和%也可以被使用,但是它們各有其特殊的用途,如果一個檔案名稱包括了這些字元( / & ? @ # $ + = %),這些字元和所有其他字元就應該被編碼。

  編碼過程非常簡單,任何字元只要不是ASCII碼數字,字母,或者前面提到的標點符,它們都將被轉換成字節形式,每個字節都寫成這種形式:一個“%”後面跟著兩位16進制的數值。空格是一個特殊情況,因為它們太平常了。它除了被編碼成「%20」以外,還能編碼為一個「+」。加號(+)本身被編碼為%2B。當/ # = & 和?作為名字的一部分來使用時,而不是作為URL部分之間的分隔符號來使用時,它們都應該被編碼。

  WARNING這種策略在存在大量字元集的異質環境中效果不甚理想。例如:在U.S. Windows 系統中, é 被編碼為 %E9. 在 U.S. Mac中被編碼為%8E。這種不確定性的存在是現存的URI的一個明顯的不足。所以在將來URI的規範當中應該透過國際資源識別碼(IRIs)來改善。

  類別URL不會自動執行編碼或解碼工作。你能產生一個URL對象,它可以包括非法的ASCII和非ASCII字元和/或%xx。當用方法getPath() 和toEx​​ternalForm( ) 作為輸出方法時,這種字元和轉移符不會自動編碼或解碼。你應對被用來產生URL物件的字串物件負責,確保所有字元都會被適當地編碼。

相關推薦:

HTTP請求頭

以上是HTTP請求頭與請求體詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!