HTTP协议基础

1. 前言

HTTP协议是一种最为常见的应用层协议,其特点是:

  • 文本协议,可读性好
  • 扩展性好
  • 应用十分广泛

HTTP协议主要分为请求包响应包,每个包都包含包头包体,使用\r\n\r\n进行分隔。

下面是使用Chrome浏览器访问https://www.baidu.com/抓到的HTTP请求包和返回包。

GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xe523220d0004f1b5
Cache-Control: private
Connection: Keep-Alive
Content-Type: text/html
Cxy_all: baidu+f77b725b5dda7a0d1796206dd5fc54c1
Date: Sat, 23 Feb 2019 06:33:26 GMT
Expires: Sat, 23 Feb 2019 06:32:35 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: BWS/1.1
Set-Cookie: BAIDUID=3B2BAAB84798D4193EDD80E73439CB3E:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BIDUPSID=3B2BAAB84798D4193EDD80E73439CB3E; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: PSTM=1550903606; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: delPer=0; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=0; path=/
Set-Cookie: H_PS_PSSID=1460_21101_28558; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Vary: Accept-Encoding
X-Ua-Compatible: IE=Edge,chrome=1
Content-Length: 156207

<!DOCTYPE html>
<!--STATUS OK-->

......

2. 包头

包头主要包含首行Headers,行间通过\r\n分隔。请求包响应包首行格式有所差别。

2.1. 首行

请求包

请求包首行格式为:

METHOD URI HTTP/x.y

METHOD是请求方法,常见的如:GETPOSTPUTDELETE等。示例中给的就是一个GET请求。

GET请求一般用于获取数据或资源的读请求,请求参数放在URI字段中;POST请求一般用于登录、提交等操作,通常会有防CSRF的字段,请求参数在包体中。

URI是要请求的资源地址,一般以/开头,只有在HTTP代理中才会使用完整的URL。

x.y是HTTP协议的版本,目前最常见的是1.1

返回包

返回包的首行格式为:

HTTP/x.y CODE MESSAGE

x.y含义与请求包一致

CODE是HTTP返回码,表示当前请求的处理结果。HTTP返回码定义请参考:HTTP返回码定义

MESSAGE一般是CODE对应的解释,也可以是自定义的内容。

2.2. Headers

这部分是可扩展的,允许用户使用自定义的HTTP头。格式一般如下:

Header-Name: header-value

Header-Name是HTTP头名称,header-value是对应的值。

请求包返回包都会出现的HTTP头

Connection : 保持连接选项,可选的值有:close(请求返回后关闭连接)、keep-alive(多个请求可以复用该连接)(注意:由于HTTP 1.x 的限制,同一个连接必须要在上一个请求返回后才能发送下一个请求)

Content-Length : 包体长度的10进制字符串,没有包体的请求可以没有该字段

Content-Type : 包体类型。常见类型如下:

  • HTML类型是text/html
  • JavaScript类型是application/javascript
  • POST请求中一般是application/x-www-form-urlencoded
  • POST上传文件时是multipart/form-data
  • RESTful请求中都是application/json

只有请求包中出现的HTTP头

Host : 要访问的主机名,如果端口不是80,需要加上:port,如:www.qq.com:8080

User-Agent : 客户端标识

Referer : 发起请求的页面url,一般用作防盗链,防CSRF

Accept : 支持的类型

Accept-Encoding : 支持的编码,如:gzipdeflatesdch等,编码间使用,分隔

Accept-Language : 支持的语言,如:zh-CN,zh;q=0.8

Cookie : cookie

只有返回包中出现的HTTP头

Server : 服务器标识

Date : 服务端响应的时间

Expires : 当前资源的过期时间

Content-Encoding : 包体的内容编码,如:gzipdeflate

Transfer-Encoding : 包体的传输编码,只能设为chunked,表示分块传输

Access-Control-Allow-Origin : 允许跨域访问的列表,如果要允许任意域名访问。可以设置为*

Access-Control-Allow-Methods : 允许跨域访问METHOD列表,如:POST, GET, OPTIONS, DELETE

Set-Cookie : 设置Cookie,格式为:key=value; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.domain.com

2.3. URL编码

GET请求中位于url的?后面的参数以及application/x-www-form-urlencoded类型的POST请求中的包体需要进行URL编码。

具体规则如下:

对于以下列表中的字符不需要处理:

ASCII Char ASCII Char ASCII Char
48 0 65 A 97 a
49 1 66 B 98 b
50 2 67 C 99 c
51 3 68 D 100 d
52 4 69 E 101 e
53 5 70 F 102 f
54 6 71 G 103 g
55 7 72 H 104 h
56 8 73 I 105 i
57 9 74 J 106 j
75 K 107 k
76 L 108 l
77 M 109 m
78 N 110 n
79 O 111 o
80 P 112 p
81 Q 113 q
82 R 114 r
83 S 115 s
84 T 116 t
85 U 117 u
86 V 118 v
87 W 119 w
88 X 120 x
89 Y 121 y
90 Z 122 z

其它字符绝大多数都需要根据字符的ASCII码转换成%.2X的格式。例如::=>%3A/=>%2F%=>%25。对于汉字等多字节字符串使用UTF8编码后再转成%.2X的形式。

对于特殊字符,不同函数的处理逻辑略有不同:

  • Python的urllib.quote

    • 只有 - . / _ 这几个字符不处理
  • JavaScript的escape

    • 只有 * + - . / @ _ 这几个字符不处理
  • JavaScript的encodeURI

    • 只有 ! # $ & ' ( ) * + , - . / : ; = ? @ _ ~ 这几个字符不处理
  • JavaScript的encodeURIComponent

    • 只有 ! ' ( ) * - . _ ~ 这几个字符不处理

3. 包体

3.1. 包体长度

包体长度的计算有两种方式:

  • 包头中存在Content-Length字段时,包体长度由该字段决定
  • 包头中存在Transfer-Encoding字段时,使用chunked方式,具体规则如下:
    • 对于每一个分块,要传输的内容为当前分块长度的16进制字符串加上\r\n,再加上分块数据和\r\n;例如分块内容为:1234567890,那么要传输的内容就为:a\r\n1234567890\r\n
    • 最后一块必须为:0\r\n\r\n

使用chunked方式的优点是:发送包头时,不用确定包体的长度,可以显著缩短TTFBTime To First Byte)值;并且对于需要动态计算包体的情况非常适合。

3.2. 包体类型

如前所述,包体的类型会由包头中的Content-Type字段决定

application/x-www-form-urlencoded 类型

该类型是POST请求中最为常见的类型,如以下所示:

staticpage=https%3A%2F%2Fwww.baidu.com%2Fcache%2Fuser%2Fhtml%2Fv3Jump.html&charset=UTF-8&tpl=mn&subpro=&apiver=v3&tt=1550929251247&codestring=&safeflg=0&u=https%3A%2F%2Fwww.baidu.com%2F&isPhone=false&detect=1

multipart/form-data 类型

该类型完整的值为:multipart/form-data; boundary=----WebKitFormBoundaryobuwoK7HliCagMDUboundary后面跟的是随机分隔字符串,用于分隔多个字段。包体内容如下所示:

------WebKitFormBoundaryobuwoK7HliCagMDU
Content-Disposition: form-data; name="bdstoken"

50463f616a435dd1586f7c25abcacb84
------WebKitFormBoundaryobuwoK7HliCagMDU
Content-Disposition: form-data; name="psign"

2d2e6472756e6b647265616d2001
------WebKitFormBoundaryobuwoK7HliCagMDU
Content-Disposition: form-data; name="staticpage"

https://www.baidu.com/p/jump.html
------WebKitFormBoundaryobuwoK7HliCagMDU
Content-Disposition: form-data; name="file"; filename="02480674.jpg"
Content-Type: image/jpeg

����

示例里共包含bdstokenpsignstaticpagefile这4个字段,其中前3个是普通字符串,file是图片文件内容。

application/json 类型

此时包体是json格式的字符串,如下所示:

{"url": "http://www.baidu.com/"}

3.3. 包体内容编码

包体的内容编码类型由Content-Encoding字段决定,主要是为了减少包体体积,提升性能。

DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。

GZIP,是一种使用 DEFLATE 的文件格式。

ZLIB,是一种使用 DEFLATE 的数据压缩格式。

gzip 压缩方式

使用GZIP格式压缩

deflate 压缩方式

其实是使用ZLIB方式压缩。由于IE错误地实现为了使用DEFLATE方式解压,因此, 为了兼容IE,Server一般都是使用gzip方式。

sdch 压缩方式

Google发明的压缩算法,全称为 Shared Dictionary Compression over HTTP,是一种基于网页HTML中存在大量冗余字符串,从而建立字典,进行压缩的方式,相对gzip等基于单文件进行压缩的方式,可以极大地提升压缩率。

目前主要是Google的服务器在使用。

4. 如何抓包

4.1. 使用Chrome抓包

Chrome浏览器自带抓包功能,可以捕获所有HTTP(S)请求,甚至是WebSocket协议。

方法是按F12打开开发者工具,进入Network页面,然后刷新页面就可以了。

这种方法抓包简单,但是只能抓取浏览器收发的包。

4.2. 使用Fiddler抓包

Fiddler是一款通过提供HTTP代理服务来抓包的工具,类似的工具还有很多,读者可以选择自己习惯的工具。

Fiddler具体的工作原理是监听了8888端口,并将其设置为系统代理。因此,浏览器在访问网页时,都会发送请求到Fiddler,从而可以捕获到请求包以及返回包。

对于HTTPS请求,Fiddler提供了HTTP CONNECT服务,进而与浏览器建立HTTPS隧道,并返回了一个自签名的证书,以绕过SSL/TLS层的加密。因此,浏览器需要忽略证书错误,才能使用Fiddler抓取HTTPS包。

Fiddler适合抓取那些使用了系统代理,并且允许证书错误的场景。如果应用限定了根证书,就无法抓包了。

4.3. 使用Wireshark抓包

Wireshark是一款驱动层的抓包工具,与tcpdump类似,适合抓取明文包,也就是HTTP包,HTTPS包由于无法解密,因此不能适用。

drunkdream.cn 版权所有 粤ICP备17153329号-1 all right reserved,powered by Gitbook该文件修订时间: 2019-02-26 19:56:02

results matching ""

    No results matching ""