本文属于原创文章,转载请注明--桃源小盼
笔者语
作为一个程序员,当我们访问一个接口,服务器接收到并返回结果,那么中间的流程是怎么处理的呢?这个请求是如何到达服务器,服务器又是怎样返回内容的?
如果没有HTTP协议,接口请求具体实现的细节, 都需要每个客户端和服务器各自约定和实现,而自己的规则,又不能适用于别人。这给开发带来了极大的不便,HTTP就是为此而设计的。HTTP协议用来约定双方的行为规范,让相关开发者按照相同的规则来开发网站和工具。
HTTP协议就像发快递时填写的发货单,规定必须填写收货人,地址和手机号码,只有这样才能准确送给收货人。HTTP则是规定了如何在两台电脑间发送和接收超文本。
起源历史
1980年,蒂姆·伯纳斯·李在CERN(欧洲核子研究组织)时,为了方便各地研究人员共享信息,提出了一个设想,"借助于超文本,连接成可互相浏览的WWW(万维网)项目"。
到了1989年,伯纳斯·李看到了将超本文与互联网结合的机会,那时已经有了在电脑上显示信息的超文本系统,也有了域名系统和TCP/IP网络传输协议。伯纳斯·李又为此设计制作世界上第一个网页浏览器和网页服务器,将这一切组合起来,就能实现浏览处于世界任何地方服务器上的超文本信息。在这个过程中,由于TCP/IP协议族中没有适合传输超文本的协议,李博士又发起了HTTP(超文本传输协议)的提议。
于是在1989年,HTTP协议诞生了。现如今最广泛使用的协议版本是在1999年制定的HTTP 1.1。
`蒂姆·伯纳斯·李在2017年4月5日,获得了2016年度图灵奖,被誉为万维网之父。他发明了浏览器,
HTTP,HTML,URI等一系列相关的万维网技术。`
TCP/IP协议族
现实世界中的各行各业都有自己的行业规则,违反规则,步履艰难,而尊重规则,便如鱼得水。网络世界也需要各种各样的规则,TCP/IP协议族就是这些规则的总称。而HTTP协议是其中的一种,负责传输超文本(HyperText)。
TCP/IP协议族一共分为四层,包含不同的协议。应用层、传输层、网络层和链路层。
这张图简单描述了,打开一个网站背后都发生了什么?
通过DNS协议,获得访问域名对应的服务器IP地址。DNS协议属于应用层。
紧接着用到了HTTP协议,将生成的HTTP报文发送给服务器。HTTP协议属于应用层。
数据在网络中的传输是十分重要的,为了保证数据传输的稳定性和完整性,制定了TCP协议,它将数据分割成报文段,按序号传输。TCP协议属于传输层。
客户端发起的请求,怎么在众多机器中找到对应那一台,需要IP协议来寻找一条路径。IP协议属于网络层。
最后服务器收到了请求,把响应内容按照之前的步骤,返回给客户端。
HTTP协议概述
客户端发出请求报文,服务器收到请求,经过处理,把响应报文返回客户端,连接断开,一次请求结束。HTTP协议是无状态协议。
在1990年W3C发布了第一个HTTP/0.9版本,这个版本只支持GET请求。
1996年发布了HTTP/1.0版本,这是第一个广泛使用的版本,支持了多媒体类型和各种HTTP首部字段。
但真正应用至今的是在1999年发布的HTTP/1.1版本,它修复了一些结构的缺陷,并引入了性能优化的措施。本文以下的内容都以HTTP/1.1为基础展开。
我们用chrome浏览器打开http://www.w3c.org
这个网站。打开开发者工具的network项,看看第一个请求的详细信息。
请求报文由请求地址、请求方法、协议版本、首部字段和内容实体。
GET /index.html HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6)
Host: w3c.org
响应报文由状态码及解释短语、协议版本、首部字段和响应实体。
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 137582
Server: Apache 0.84
<html>
<body>Hello World</body>
</html>
HTTP请求方法
HTTP/1.1 支持多种请求方法,最常用的还是get和post方法。
HTTP通信是建立在TCP连接的基础上,早期版本每次通信都需要重新连接、断开TCP。所以在HTTP/1.1下,实现了在一次TCP连接中进行多次HTTP通信的能力,大大提高了服务器的响应速度。同时也支持并行发送请求,一般浏览器是支持同时6个连接。
GET
gee方法是安全的请求方法,获取已经存在的资源或者是查询一些数据,通常会把请求参数拼接在url中。
HEAD
head方法也是安全的,但它与get的不同在于,它不会返回响应实体内容,只返回响应首部。一般会用来确认请求url的有效性。
POST
post方法会把请求内容放在请求实体中,而不是拼接在url中。所以一般查询信息用GET方法,提交表单数据使用post方法。
OPTIONS
查询指定url资源支持的请求方法,例如支持get和head。
TRACE
一般请求发出后,会经过多层代理服务器,这个方法就是用来确认请求发出后发生的一系列操作。但会引起跨站追踪攻击,一般不用。
PUT与DELETE
put是用来往服务器上传文件,而delete就是删除服务器上的文件。但是这两个方法没有验证机制,会产生不安全问题,一般服务器都不做支持。
状态码
状态码用来表示服务器返回的请求结果。由三位数字加解释短语组成,例如 200 ok。
虽然状态码有很多,但是也可分门别类,并不需要掌握所有,也对返回的结果有个大致的了解。
状态码 | 响应类别 | 原因短语 |
---|---|---|
1xx | 信息性状态码(Informational) | 服务器正在处理请求 |
2xx | 成功状态码(Success) | 请求已正常处理完毕 |
3xx | 重定向状态码(Redirection) | 需要进行额外操作以完成请求 |
4xx | 客户端错误状态码(Client Error) | 客户端原因导致服务器无法处理请求 |
5xx | 服务器错误状态码(Server Error) | 服务器原因导致处理请求出错 |
当我们知道了,首位数字是定义状态码的类型后,理解更多的状态码也就简单起来。
下面,再详细介绍一些常见的状态码。
200 OK
这个是最常见的,表示请求在服务器被正确处理了。
204 No Content
请求在服务器端被正确处理了,但是返回的响应报文中没有实体内容。一般用在只是客户端向服务器发送信息,而服务器不用向客户端返回什么信息的情况。
301 Moved Permanently
永久性重定向,代表资源的链接已经更换了url,在响应报文中会包含新的链接地址。
304 Not Modified
当发出的请求中有附加条件(首部字段有if-*)时,服务器允许访问,但是不满足条件的情况。
400 Bad Request
请求报文内容存在语法错误,服务器处理不了。
401 Unauthorized
发送的请求中含有HTTP认证信息,认证未通过。
返回401的响应必须包含一个适用于被请求资源的WWW-Authenticate首部以质询用户信息
403 Forbidden
请求的资源拒绝被访问,一般是无权限访问。
404 Not Found
这个也很常见,请求的资源服务器找不到。
500 Internal Server Error
服务器在处理请求时,出错了。一般是服务器发生了异常状况。
HTTP首部
首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。通俗点讲,浏览器和服务器会根据这些字段做出不同的反应,每个字段相当于一条配置信息。
首部字段类似于键值对,请求报文和响应报文都包含首部信息。
这是一段请求首部字段,例如Accept表示浏览器可以接受的响应报文实体类型。
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Host:www.w3.org
If-Modified-Since:Thu, 04 May 2017 23:40:12 GMT
If-None-Match:"a384-54ebb4b41af00;89-3f26bd17a2f00-gzip"
首部字段分为了五种类型,通用首部、请求首部、响应首部、实体首部和拓展首部。
类型 | 说明 |
---|---|
通用首部 | 是请求和响应都会用到的字段 |
请求首部 | 是客户端向服务器发送请求时,报文中包含的首部字段 |
响应首部 | 是服务器向浏览器返回响应报文时,包含的首部字段 |
实体首部 | 是请求报文和响应报文中针对实体内容的首部字段 |
拓展首部 | 是非标准首部字段,由开发者根据自身需求自由定义和实现 |
以下列表,提供一些首部的简单说明,每个字段的具体使用都不一样,实际应用还是查看详细介绍。
通用首部
字段名 | 说明 |
---|---|
Cache-Control | 控制缓存行为 |
Pragma | HTTP/1.0遗留字段,也是用于控制缓存机制 |
Transfer-Encoding | 传输报文主体的编码方式 |
Trailer | 报文主体之后的首部字段,用于分块传输 |
Upgrade | 检测HTTP协议是否可用更高版本 |
Connection | 控制不再转发给代理的字段、连接的管理 |
Date | 创建报文的日期 |
Via | 追踪客户端与服务器之间报文的传输路径,通常指代理服务器 |
Warning | 缓存相关警告 |
请求首部
字段名 | 说明 |
---|---|
Accept | 客户端可接受的媒体类型及相关优先级,q值表示权重 |
Accept-Charset | 客户端可接受的字符集及优先顺序 |
Accept-Encoding | 客户端支持的内容编码及优先顺序 |
Accept-Language | 客户端可处理的自然语言集,以及优先级 |
Authorization | 客户端的认证信息,一般是证书信息 |
Host | 请求资源所在服务器的主机名和端口号 |
If-Match | 比较实体标记 |
If-Modified-Since | 比较资源更新时间 |
If-None-Match | 比较实体标记(与If-Match作用相反) |
If-Range | 资源未更新时发送实体Byte的范围请求 |
If-Unmodified-Since | 比较资源更新时间(与If-Modified-Since作用相反) |
Max-Forwards | 最大传输逐跳数(TRACE或OPTIONS方法会用到) |
Range | 范围请求的实体字节段 |
Referer | 请求页面的原始url |
TE | 传输编码及优先级 |
User-Agent | 请求客户端的自身信息 |
响应首部
字段名 | 说明 |
---|---|
Accept-Ranges | 服务器是否接受字节范围请求 |
Age | 服务器响应创建经过的时间 |
ETag | 资源配置信息 |
Location | 服务器告知客户端重定向url |
Proxy-Authorization | 代理服务器向客户端发起的认证信息 |
Retry-After | 服务器告知客户端再次请求的时间 |
Server | 服务器应用名、版本号等相关信息 |
Vary | 代理服务器的缓存管理信息 |
WWW-Authorization | 服务器对客户端的认证信息 |
实体首部
字段名 | 说明 |
---|---|
Allow | 资源支持的请求方法 |
Content-Encoding | 实体内容的编码方式 |
Content-Language | 实体内容的自然语言集 |
Content-Length | 实体内容字节长度 |
Content-Location | 实体内容替代url |
Content-MD5 | 实体内容的报文摘要 |
Content-Range | 实体内容的位置范围 |
Content-Type | 实体内容对应的媒体类型 |
Expires | 实体内容失效日期 |
Last-Modified | 实体内容最后修改日期 |
Cookie
HTTP协议是无状态的,如果我们今天登录了一个网站,明天重新打开网站时,能自动登录,怎么办?
那就得靠cookie来解决了。它能在客户端保存用户的基本信息,当我们下次访问该网站,浏览器会把cookie一起发送给服务器,服务器就会根据这些信息来判断你是否登陆过。
cookie是网景公司的前雇员卢·蒙特利在1993年3月的发明的。cookie数据也是键值对的形式,它和网站以及网页是关联在一起的。如果保存cookie值指定了网站地址,访问其他网站时并不会发送这些cookie值。
访问一个网站,打开chrome的开发者工具,application中可以看见cookie的信息。
cookie相关的首部字段
Expires:是用来设置cookie的绝对过期时间,默认cookie的生存周期是跟随页面的,页面关闭即失效。
Max-Age:是用来设置cookie的相对过期时间,如果同时设置了Expires值,以Max-Age为准。
path: 是用来指定与cookie绑定的网页地址,默认情况下,和该网页同一目录下的网页也能访问该cookie。
domain: 指定与该cookie绑定的域名,该域名下的网页都可以访问该cookie。
secure: 标明传输cookie值的方式。默认情况下,cookie是在不安全的HTTP链接传输,如果设定了该值,cookie将必须处于更安全的方式下才可以传输,比如接下来介绍的HTTPS。
cookie的缺陷
传输:cookie在每一次的HTTP请求中都被附加发送,增加了传输流量。
安全:cookie是明文传输,有安全性问题,会被劫持和篡改。
大小:cookie有大小限制是4kb,更复杂的数据存储是无法满足的。
HTTPS
HTTP协议传输的数据是明文未加密的,为了安全性,网景公司设计了SSL协议(安全套接层),用SSL建立一个安全的通信线路后,就可以在这条线路上进行普通的HTTP通信了,与SSL组合起来就是 HTTPS了,不过现在使用更多的是TLS(安全层传输协议)。
网站使用HTTPS需要申请一个证书,由第三方的可信赖机构提供的,这是为了防止身份伪装。
HTTPS的握手过程
客户端发送协议版本,随机码,支持的加密算法和压缩方法
服务器确认使用的协议版本和加密算法,生成随机码,发送服务器证书
客户端验证服务器证书,生成48字节key,使用服务器公钥加密key,发送加密信息,客户端握手结束
服务器将两个随机码+key组合生成本次通信密钥,用来加密信息,服务器握手结束
接下来的通信都将在此加密通信下进行,以上任何确认过程失败,都将断开加密通信。
插曲OpenSSL
看过锤子发布会的,都知道这个组织,但具体干什么的恐怕也没几个人清楚。它是HTTPS中SSL和TLS的具体实现库。
OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,其主要库是以C语言所写成,实现了基本的加密功能,实现了SSL与TLS协议。OpenSSL可以运行在绝大多数类Unix操作系统上,OpenVMS与 Microsoft Windows。
未来的HTTP/2
随着互联网的发展,web页面的数据量暴增,服务多年的HTTP/1.1已经显露疲态,由于协议是固定的,所以浏览器,服务器和开发者等都通过各自的手段,来加强服务的响应能力,减缓HTTP/1.1的不足之处。
谷歌开发了SPDY这个实验性协议来提升http的性能,HTTP/2的草案就是基于SPDY3.0展开的。HTTP/2的主要目标是改进传输性能,实现低延迟和高吞吐量。升级HTTP2不会影响原有的网站应用。
二进制分帧
HTTP/2将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码。之前版本的数据传输都是纯文本的方式,二进制的解析更高效,更准确。这是整个HTTP/2性能提升的基础。
多路复用的流
当前问题:
HTTP/1.1协议中,一个tcp连接处理一个HTTP请求。例如同时有A和B两个请求,先发送A请求,A请求响应结束,再发送B请求,如果A请求处理的时间很长,B也只能等待,这样就造成了线头堵塞。目前每个浏览器可以同时发起6-8个tcp连接,也依然不能很好地解决大量请求的处理。就算开启了管道机制,一个tcp连接同时发送A和B请求,B还是会等在A之后响应。
HTTP/2的方式:
HTTP/2中的请求都在一个tcp连接中处理,每个请求和响应都被分解为独立的帧,然后并行交错发送,再在另一端重新组装。请求之间不再互相干扰,从而消除了不必要的等待和延迟,巨大地提升了性能。
头部压缩
由于HTTP是无状态的,所以每一次请求和响应都会携带头信息,而其中很多头信息是相同的,毫无疑问增加了传输的数据量。
所以HTTP/2设计了专门用于压缩头信息的HPACK算法,在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,并进行更新替换。
服务器推送
当我们访问一个网页时,服务器先返回HTML文档,浏览器再根据这个文档,去请求其中包含的图片,样式表和脚本。
而HTTP/2中,服务器可以对一个客户端发送多个响应,而无需客户端再多起多次请求,客户端可以控制该功能的开启。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。