http是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP之上的Web应用。
HTTP请求一般经过3个关卡,分别为DNS、Nginx、Web服务器,具体流程如下图:
- 浏览器发送请求首先到达当地运营商DNS服务器,经过域名解析获取请求 IP 地址
- 浏览器获取 IP 地址后,发送HTTP请求到达Nginx,由Nginx反向代理到Web服务端
- 最后,由web服务端返回相应的资源

浏览器发起请求-> 解析域名得到ip进行TCP连接 ->浏览器发送HTTP请求和头信息发送->服务器对浏览器进行应答,响应头信息和浏览器所需的内容-> 关闭TCP连接或保持-> 浏览器得到数据数据进行操作
一、协议各层
1.应用层
应用层作为TCP/IP的最上层,由于在传输层的传输协议大致分成了TCP和UDP,所以在应用层对应的协议也就分成了2部分:
运行在TCP协议上的协议:
HTTP(Hypertext Transfer Protocol),用于普通浏览。
HTTPS(Hypertext Transfer Protocol over Secure Socket Layer, or HTTP over SSL,安全超文本传输协议),HTTP协议的安全版本。
FTP(File Transfer Protocol),用于文件传输。
POP3(Post Office Protocol, version 3,邮局协议),收邮件用。
SMTP(Simple Mail Transfer Protocol),用来发送电子邮件。
TELNET(Teletype over the Network,网络电传),通过一个终端(terminal)登陆到网络。
SSH(Secure Shell,用于替代安全性差的TELNET),用于加密安全登陆用。
运行在UDP上的协议:
BOOTP(Boot Protocol),用于无盘设备。
NTP(Network Time Protocol),用于网络同步。
DHCP(Dynamic Host Configuration Protocol),动态配置IP地址。
2.网络层
ICMP是IP的附属协议。网络层用它来与其他主机或路由器交换错误报文和其他重要信息
二、发包流程
0.DNS地址解析

如客户端浏览器请求浏览页面:www.baidu.com。其实这是一个默认路径,因为平常默认会省略协议名、端口号,访问主页的时候路径也会省略,所以完整路径写法是www.baidu.com:80/index.html。这就是常说的URL统一资源定位符,用来定位访问资源在服务器上的位置。
从这个URL中可分解出协议名、主机名、端口号、访问对象的路径
http://host[":"port][abs_path]
http:表示要通过HTTP来定位网络资源;
host:表示合法的Internet主机域名或IP地址;如www.baidu.com
port:指定一个端口号,为空则使用默认端口80;
abs_path:指定请求资源的URI。若URL中未给出abs_path,那么当它作为请求URI时,必须以“/”的形式给出,通常这个工作浏览器自动完成。如/index.html
eg:
1、输入:www.guet.edu.cn
浏览器自动转换成:http://www.guet.edu.cn/
注意:
a)首先会搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1min,且只能容纳1000条缓存)
b)若浏览器自身的缓存里面没找到,那么浏览器会搜索系统自身的DNS缓存
c)若还没找到,那么尝试从 hosts文件里面去找
d)在前面3个过程都没获取到的情况下,就递归地去域名服务器去查找
1. 建立TCP连接(先DNS查询再3次握手)
HTTP 是比 TCP 更高层次的应用层协议,根据规则,只有低层协议建立后才能进行更高层协议的连接,因此,首先要建立 TCP 连接,一般TCP连接的端口号是80。建立TCP连接需找到连接主机,所以需先解析域名得到 IP 再找到主机进行3 次握手建立TCP连接(2台电脑之间建立一个通信桥梁)
2. Web浏览器向Web服务器发送封装的http请求
HTTP请求报文由4部分组成:
请求行
请求方法、请求地址、HTTP版本,如:GET/books/java.html HTTP/1.1(CRLF)
请求头
用于描述客户端请求哪台主机,以及客户端的一些环境信息(User-Agent)等(之后浏览器发送一空白行来通知服务器,表示结束了该头信息的发送)
注:Connection设置为 keep-alive用于说明 客户端这边设置的是,本次HTTP请求后并不需关闭TCP连接,这样可使下次HTTP请求使用相同的TCP通道,节省TCP建立连接的时间
空行
请求正文
当使用POST, PUT等方法时,通常需客户端向服务器传递数据。这些数据就储存在请求正文中(GET方式是保存在url地址后面,不会放到这里)
注:客户端发给服务端的请求数据,这部分数据并不是每个请求必须的(GET请求就没)

请求方法
(所有方法全为大写)有多种,各个方法的解释如下:
GET
请求获取Request-URI所标识的资源
eg:GET /form.html HTTP/1.1 (CRLF)
POST
在Request-URI所标识的资源后附加新的数据,常用于提交表单
eg:POST /reg.jsp HTTP/ (CRLF)
HEAD
请求获取由Request-URI所标识的资源的响应消息报头。利用这个方法,不必传输整个资源内容,就可得到Request-URI所标识的资源的信息。该方法常用于测试超链接的有效性,是否可访问,以及最近是否更新。
PUT
请求服务器存储一个资源,并用Request-URI作为其标识
DELETE
请求服务器删除Request-URI所标识的资源
TRACE
请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT
保留将来使用
OPTIONS
请求查询服务器的性能,或查询与资源相关的选项和需求
请求方法最常用的有Get 和Post 2种。
2个方法在传输形式上有一些区别,通过Get方法发起请求时,会将请求参数拼接在request-url尾部,格式是url?param1=xxx¶m2=xxx&[…]。
这样传输参数会使得参数都暴露在地址栏中。并且由于url是ASCII编码的,所以参数中若有Unicode编码的字符,例如汉字,都会编码后传输。注意,虽然http协议并没有对url长度做限制,但是一些浏览器和服务器可能会有限制,所以通过GET方法发起的请求参数不能太长。而通过POST方法发起的请求是将参数放在请求体中的,所以不会有GET参数的这些问题。
另外一点差别就是方法本身的语义上的。GET方法通常是指从服务器获取某个URL资源,其行为可看作是一个读操作,对同一个URL进行多次GET并不会对服务器产生什么影响。而POST方法通常是对某个URL进行添加、修改,例如一个表单提交,通常会往服务器插入一条记录。多次POST请求可能导致服务器的数据库中添加了多条记录。所以从语义上来讲,2者不能混为一谈。
请求头
常见请求头如下:

下面是一个POST方法的请求报文:
POST /index.php HTTP/1.1 请求行
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2 请求头
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://localhost/
Content-Length:25
Content-Type:application/x-www-form-urlencoded
空行
username=aa&password=1234 请求数据
3. Web服务器应答
HTTP响应也由3部分组成:状态行,响应头和响应正文

状态行
HTTP版本、状态码、状态描述,如:HTTP/1.1 200 OK
响应头
描述服务器的基本信息,以及客户端如何处理数据,最后发送一个空白行来表示头信息的发送到此为止
空行
响应正文
以Content-Type响应头信息所描述的格式发送用户所请求的实际数据。服务器返回给客户端的数据
状态行
格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
HTTP-Version:服务器HTTP版本;
Status-Code:服务器发回的响应状态代码;
Reason-Phrase:状态代码的文本描述。
状态码
由3位数字组成,第一个数字定义了响应的类别,且有5种可能取值:
1xx
指示信息--表示请求已接收,继续处理
2xx
成功--表示请求已被成功接收、理解、接受
200 OK //客户端请求成功
3xx
重定向--要完成请求必须进行更进一步的操作
4xx
客户端错误--请求有语法错误或请求无法实现
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
5xx
服务器端错误--服务器未能实现合法的请求
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
eg:HTTP/1.1 200 OK (CRLF)
常见响应头部如下:

下面是一个响应报文的实例:
HTTP/1.1 200 OK 状态行
Date: Sun, 17 Mar 2017 08:12:54 GMT 响应头部
Server: Apache/2.2.8 (Win32) PHP/5.2.5
X-Powered-By: PHP/5.2.5
Set-Cookie: PHPSESSID=c0huq7pdkmm5gg6osoe3mgjmm3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 4393
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
空行
<html> 响应数据
<head>
<title>HTTP响应示例<title>
</head>
<body>
Hello HTTP!
</body>
</html>
4.浏览器解析html代码,并请求html代码中的资源
浏览器拿到html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,就向服务器端去请求下载(会使用多线程下载,每个浏览器的线程数不一样),这时就用上 keep-alive特性了,建立一次HTTP连接,可请求多个资源,下载资源的顺序就是按照代码里面的顺序,但由于每个资源大小不一样,而浏览器又是多线程请求请求资源,所以这里显示的顺序并不一定是代码里面的顺序
5. Web服务器关闭TCP连接
一般情况下,一旦 Web 服务器向浏览器发送了请求的数据,它就要关闭 TCP 连接,但若浏览器或服务器在其头信息加入了这行代码:Connection:keep-alive
TCP连接在发送后将仍保持打开状态,于是,浏览器可继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需时间,还节约了网络带宽。
6. 浏览器接受到服务器响应的数据
浏览器接受服务器应答回来的 html 代码和css,和js代码再进行页面的渲染或接受到应答的文件进行保存等操作
3、通过Wireshark抓包对一次完整HTTP网络请求过程的验证
1.域名解析


响应报文如下:

可看到,经过DNS查询,得到了IP地址123.125.103.192 和111.202.1.201
2.tcp的3次握手
一般在dns查询成功后的建立的第一条tcp流即是对应的流

3. 发起HTTP请求
发起GET请求,请求格式:分别是请求行、请求头、空行、消息体,每部分内容占一行。下图是抓取的请求报文。可看到,请求方法为GET,协议版本是HTTP/1.1,主机名www.xiaomi.com,User-Agent是生成请求的浏览器类型,Accept是客户端可识别的响应内容类型列表。Accept-Language: 客户端可接受的自然语言。Accept-Encoding: 客户端可接受的编码压缩格式。connection:连接方式

下图是响应报文,可看到的请求被重定向到了www.mi.com

收到响应报文后,发现的请求被重定向到了www.mi.com
所以,要去访问www.mi.com,所以再来一遍DNS查询,TCP连接。抓包结果如下:

那么与www.mi.com建立了连接后呢,就可开始传输数据了吗?并不是。
在数据传输之前,要建立加密安全数据通道,这就要用到TLS协议。
分析TLS报文
客户端会先向服务端发送Client Hello消息,其中包括了随机数、密码套件以及密钥交换算法参数。服务端收到后会给确认,发送给客户端Server Hello 数据包,服务端会根据Client Hello提供的协议版本列表,选择版本。
下图是TLS协议Client Hello。

下图是服务端发出的Server Hello

到此,TLS的握手过程就结束了,后面可加密传输消息了。
4.服务器响应HTTP请求

5.四次挥手
