HTTP协议
Web浏览器和Web服务器程序进行数据交换,发送请求和应答时,要遵循一定的协议(不然也无法解析数据),这个协议就是超文本传输协议(Hyper Text Transfer Protocol, HTTP).
HTTP协议使用TCP协议作为支持,为其提供可靠的数据传输服务。
-
Web浏览器和Web服务器
HTTP1.1特性
- 应用层协议: HTTP工作在应用层, 运输层使用TCP协议, 默认端口为80
- 基于C/S模式: 客户端通过浏览器(并非一定是浏览器)向服务器发出请求, 服务器向客户端返回对请求的应答。
- 双向传输: 客户端向服务器发送请求, 服务器向客户端回应信息, 客户端负责将回应信息解析呈现给用户。客户端也可以将诸如表单一类的信息发送给服务器。
- 支持多个主机名: HTTP1.1版本允许一个Web服务器处理几十个甚至几百个虚拟机的请求。
- 持久连接:允许客户机在一个TCP连接中发送多个相关文档的请求。 HTTP1.0以前的版本一个请求需要一个新的TCP连接。
- 部分资源选择: 允许客户机只要求文档的部分资源的请求, 这样可以减少服务器的负载, 节省了资源。
- 支持高速缓存的代理: Web浏览器将用户浏览过的网页内容缓存在本机高速缓存中; 亦可在客户机和服务器之间建立代理服务器, 将本网络中曾经访问过的网页缓存在本地代理服务器中,客户端优先从代理服务器中读取信息, 减少不必要的Internet访问流量。
- 内容协商: 通过内容协商特性完成客户机和服务器的信息交换, 确定传输的细节。
- 安全性好:使用鉴别方法提高安全性能。
HTTP的工作过程
- 客户机与服务器交互过程
- Web服务器监听本地80端口。等待请求。
- 建立连接。由TCP协议建立连接, 开启一条传输通道, 提供数据传输的保障。
- 客户端发出请求。连接建立后, 即可向服务器发出请求, 获取数据。请求封装在HTTP请求报文中。
- Web服务器应答请求。 收到请求后, Web服务器将应答和对应文件放入HTTP应答报文中, 发送给客户端。
- 重复3, 4
- 通信结束, 关闭连接。
HTTP无状态特性
服务器不去记录访问的客户端。
持久连接和非持久连接
HTTP1.1默认使用持久连接。
- 持久连接
可一次连接请求多个文件
- 非持久连接
每次连接只能请求一个文件
HTTP报文
报文有请求和应答两种。一般以文本形式发送。
请求报文
客户端使用,指明所需文档的名字和位置。
-
报文结构
GET报文
最常用的的报文,请求参数以?para=val¶2=val2的形式加在URL后面。实体是空的,GET方式一般用来请求数据。当然要用来提交数据也没有人可以阻止你就是了。。。
- Host: 表示所要访问的主机。Host字段与方法字段结合,可以明确要访问的资源。如上图中一个完整的URL应当是:http://i0.wp.com/ooly.club/pzyyll/wp-content/uploads/2016/04/cropped-b_authentique1.jpg?resize-825%2c510
- Connection: 告诉服务器对客户端做出应答后,是否保持连接,上图中的Keep-Alive,表示保持连接。例如一个网页文件中可能有多个图片连接,保持连接可以不断开连接而继续下载图片文件,提高效率和响应速度。
- Accept: 表示客户端所接受的文档类型。常见的还有 image/gif, image/jpeg, application/vnd.ms-word等等。
- User-Agent: 表示客户端类型。可以用于让服务器根据客户端类型返回应答内容,防止出现客户端无法理解应答的现象。
- Referer: HTTP參照位址(referer,或HTTP referer),是HTTP表頭的一個欄位,用來表示從哪兒連結到目前的網頁,採用的格式是URL。換句話說,藉著HTTP參照位址,目前的網頁可以檢查訪客從哪裡而來,這也常被用來對付偽造的跨網站請求。
- Accept-Encoding: 表示客户端能够理解的编码方式。
- Accept-Language: 表示客户端优先接受的语言类型, 服务器可以根据语言的不同返回不同版本的主页。
POST报文
另一个最常用的请求报文,一般用于提交数据,或请求参数比较敏感的,例如密码信息等。因为用POST方式提交的数据都会放在请求报文的实体中。
POST报文的首部行还常常会用到下面这个:
- Content-type: (实体解析类型)
详细表单内容类型
较为常用的就是以下两种:- application/x-www-form-urlencoded
- multipart/form-data
- 另外还有
- application/json
- text/xml
- 等等
用一个例子作为说明,比如我要传递一个下面的表单信息:
Name:Zhili Cai
Pwd:1234567
Email: pzyyll@gmail.com
1.application/x-www-form-urlencoded: 用这种方式的实体内容的键值对用“KEY=VAL&KEY2=VAL2&..."的方法表示。并且会对KEY和VAL中的某些字符进行URI Encoding转义,具体有哪些可以参照这个,对于空格的处理是转换为‘+’.
POST /post.php HTTP/1.1/r/n
...
Content_type: charset=utf-8; application/x-www-form-urlencoded/r/n
/r/n //记得首部行与实体之间空一行
Name=Zhili+Cai&Pwd=1234567&Email=+pzyyll%40gmail.com
2.multipart/form-data:这种方式的实体就稍微有点复杂了,除了要指明content_type外,还要设置一个分隔字符串boundary,详细见下面:
POST /post.php HTTP/1.1
...
Content_type: multipart/form-data; boundary=abcdefghijklmn
//实体与首部行之间空一行
--abcdefghijklmn //分割符前还要再加--
Content-Disposition: form-data; name="Name"
//内容与首部行之间空一行
Zhili Cai
--abcdefghijklmn
Content-Disposition:form-data; name="Pwd"
1234567
--abcdefghijklmn
Content-Disposition:form-data; name="Email"
pzyyll@gmail.com
--abcdefghijklmn-- //结束--boundary--
另外boundary还可以嵌套,以下是摘自官方文档的
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Larry
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=BbC04y
--BbC04y
Content-Disposition: file; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--BbC04y
Content-Disposition: file; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
--AaB03x--
Content-Disposition 用来指示出内容的类型,例如还有attachment,表示附件。具体可以查看文档
3.application/json: 需要浏览器和服务器支持
POST /post.php HTTP/1.1
...
Content_type: charset=utf-8; application/json
//记得首部行与实体之间空一行
{"Name":"Zhili Cai", "Pwd":"1234567", "Email":" pzyyll@gmail.com"}
其它的请求方法还有HEAD, PUT, DELETE等
- HEAD:与GET类似,但是应答报文无实体内容,一般用于检测URI是否有效,能否被访问。
- PUT:用于将一个文档上传到服务器上,文档内容存储在实体中, 服务器根据URI创建一个新文档,并将实体内容存入新文档中,如果文档在服务器上已经存在,则会覆盖旧文档。执行成功返回对应的应答报文,失败则报错。
- DELETE:用来删除服务器上的文档。
各种方式可以查看RFC2616的第9章
应答报文
结构与请求报文类似,但是第一行是状态行,不是请求行了。
一个实例:
--> HTTP/1.1 302 Found
Server: nginx
Date: Wed, 04 May 2016 06:06:52 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.4.41
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
Set-Cookie: [52 bytes were stripped]
X-Frame-Options: SAMEORIGIN
Set-Cookie: [257 bytes were stripped]
Set-Cookie: [247 bytes were stripped]
Set-Cookie: [249 bytes were stripped]
Location: http://ooly.club/pzyyll/wp-admin/
另外再补充下,现在的HTTP协议已经到版本2了,请求行和状态行,首部行和现在的不太一样
感兴趣的可以查看文档RFC7540
GET /resource HTTP/1.1 HEADERS
Host: example.org ==> + END_STREAM
Accept: image/jpeg + END_HEADERS
:method = GET
:scheme = https
:path = /resource
host = example.org
accept = image/jpeg
/******************************************************/
POST /resource HTTP/1.1 HEADERS
Host: example.org ==> - END_STREAM
Content-Type: image/jpeg - END_HEADERS
Content-Length: 123 :method = POST
:path = /resource
{binary data} :scheme = https
CONTINUATION
+ END_HEADERS
content-type = image/jpeg
host = example.org
content-length = 123
DATA
+ END_STREAM
{binary data}
/******************************************************/
HTTP/1.1 100 Continue HEADERS
Extension-Field: bar ==> - END_STREAM
+ END_HEADERS
:status = 100
extension-field = bar
HTTP/1.1 200 OK HEADERS
Content-Type: image/jpeg ==> - END_STREAM
Transfer-Encoding: chunked + END_HEADERS
Trailer: Foo :status = 200
content-length = 123
123 content-type = image/jpeg
{binary data} trailer = Foo
0
Foo: bar DATA
- END_STREAM
{binary data}
HEADERS
+ END_STREAM
+ END_HEADERS
foo = bar
首部行中还有一个Cookie来记录用户行为,现在也用的比较广。