本文主要和大家分享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)分為三個部分:請求方法、請求位址和協定及版本,以CRLF(rn)結束。
HTTP/1.1 定義的請求方法有8種:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常的兩種GET和POST,如果是RESTful介面的話一般會用到GET、 POST、DELETE、PUT。
注意,只有POST、PUT以及PATCH這三個動詞時會包含請求體,而GET、HEAD、DELETE、CONNECT、TRACE、OPTIONS這幾個動詞時不包含請求體。
Header | 解釋 | ##範例|
---|---|---|
指定客戶端能夠接收的內容類型 | Accept: text/plain, text/html,application/json | |
瀏覽器可以接受的字元編碼集。 | Accept-Charset: iso-8859-5 | |
指定瀏覽器可以支援的web伺服器傳回內容壓縮編碼類型。 | Accept-Encoding: compress, gzip | |
瀏覽器可接受的語言 | Accept-Language: en,zh | |
可以請求網頁實體的一個或多個子範圍欄位 | Accept-Ranges: bytes | |
HTTP授權的授權憑證 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== | |
指定要求和回應遵循的快取機制 | Cache-Control: no-cache | |
##表示是否需要持久連線。 (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 | #發出請求的使用者的Email | From: user@email.com |
#Host | 指定要求的伺服器的網域名稱和連接埠號碼 | Host: www.zcmhi.com |
If-Match | 只有請求內容與實體相符才有效 | If-Match: 「737060cd8c284d8af7ad3082f209582d」 |
If-Modified-Since | #如果要求的部分在指定時間之後被修改則要求成功,未被修改則傳回304碼 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果內容未改變回傳304程式碼,參數為伺服器先前發送的Etag,與伺服器回應的Etag比較判斷是否改變 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
#If-Range##If-Range | ###如果實體未改變,伺服器發送客戶端遺失的部分,否則發送整個實體。參數也為Etag | If-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 |
根据应用场景的不同,HTTP请求的请求体有三种不同的形式。
移动开发者常见的,请求体是任意类型,服务器不会解析请求体,请求体的处理需要自己解析,如 POST 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 方式提交数据。如有需要,可以参考这篇文章。
我的博客之前提到过 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 会更灵活方便。
這算是最常見的 POST 提交資料的方式了。瀏覽器的原生