http文档:https://tools.ietf.org/html/rfc2616
1.前言
这篇文章主要是我平时在学习HTTP过程中看到的一些知识点,现在把他们总结成一篇文章,建立一个自己的知识体系。
1.1基础知识铺垫
OSI是Open System Interconnection的缩写,意为开放式系统互联。
OSI有7层框架 如图:
1)应用层(dns,http)DNS解析域名为IP并发送http地址
2)传输层(tcp,udp)建立tcp连接(三次握手)
3)网络层(IP,ARP)IP寻址
4)数据链路层(PPP)封装成帧
今天的主角是http:http是基于TCP/IP协议的应用层协议,用于客户端和服务器之间的通信。HTTP是一个无状态的协议。
1.2在TCP/IP协议栈中的位置
HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。如下图所示:
默认HTTP的端口号为80,HTTPS的端口号为443。
2. HTTP发展历程
- HTTP/0.9版本,这个时候的HTTP只支持
GET
请求,且不支持请求头, - HTTP/1.0版本,这是第一个在通讯中指定版本号的HTTP协议版本,至今仍被广泛采用,特别是在代理服务器中。
- HTTP/1.1版本,持久连接被默认建立,并能很好地配合代理服务器工作。还支持以管道方式在同时发送多个请求,以便降低线路负载,提高传输速度。现在使用最广泛的。
- HTTP/2.0版本,当前版本,于2015年5月作为互联网标准正式发布。
3.HTTP请求
HTTP
请求第一步,应该是由客户端发起一个HTTP
请求,当然这个客户端可以是例如我们的浏览器,F12调试,发起我们的第一个请求头信息。
http报文一般包括:通用头部、请求/响应头部、请求/响应体
假设我们现在开始请求CSDN主页
通用头部:
请求头部
响应头部
说一点:Content-Length当浏览器使用持久http连接才需要。
如果存在Transfer-Encoding(重点是chunked),则在header中不能有Content-Length,有也会被忽视
这里插一句,HTTP/1.1
沿用的是文本类型的请求头,HTTP/2
则会使用二进制数据。
4.HTTP是如何建立连接的
说道如何连接的,我们必须要回顾一个东西,那就是大学学到过的计算机网络基础,几乎所有的大学生
都应该了解过计算机的网络模型,也就是我们熟知的七层网络模型
,如下图
但是计算机网络中的七层模型毕竟是理想中的情况,现实是很少有应用实现了七层模型,一般都是整合其中两个或多个,实现一个四层或者五层的模型。
TCP/IP模型
在这里我们研究的是HTTP
,自然要知道它所处在哪个模型中,答案是应用层
。这里要引入一个TCP/IP
的概念,大家应该知道,TCP
处于传输层,IP
属于网络层,而我们这里所探究的HTTP
,实际上就是基于TCP/IP
协议开发的,至于TCP/IP
的网络模型,它没有照搬计算机网络的七层模型,而是整合了表示层
,会话层
,应用层
,统一为应用层,比较有争议的是,关于TCP/IP
究竟是几层协议,目前为止没有定论,一般我比较习惯统称为四层协议,至于别人说的五层协议,其实就是数据链路层
,物理层
是不是一层有所争议吧。如图:
因为HTTP
是基于TCP/IP
开发的协议,看过HTTP
协议的同学肯定都知道,有句话概述HTTP
协议为无差错的协议
,按序传输
,未分段的数据流
,这其实说的就是TCP
协议。
5 发送一条HTTP请求会发生什么?
当你在浏览器输入一个URL
的时候,有没有想过这其中发生了什么?
-
获取主机名,例如:
http://www.nowamagic.net/academy/
-
通过
DNS
获取服务器IP
- 获取端口,默认是80端口
-
连接到
121.199.24.143:80
服务器 -
通过
TCP
信道发送一个HTTP
请求 -
服务器读取一个
HTTP
请求 -
服务器查找所需资源并通过
TCP
信道返回资源 -
关闭
TCP
连接
6 .字段解释
通用头部
这也是开发人员见过的最多的信息,包括如下:
Request Url: 请求的web服务器地址
Request Method: 请求方式(Get、POST、OPTIONS、PUT、HEAD、DELETE、CONNECT、TRACE)
Status Code: 请求的返回状态码,如200代表成功
Remote Address: 请求的远程服务器地址(会转为IP)
这里面最常用到的就是状态码,很多时候都是通过状态码来判断,如(列举几个最常见的):
200——表明该请求被成功地完成,所请求的资源发送回客户端
304——自从上次请求后,请求的网页未修改过,请客户端使用本地缓存
400——客户端请求有错(譬如可以是安全模块拦截)
401——请求未经授权
403——禁止访问(譬如可以是未登录时禁止)
404——资源未找到
500——服务器内部错误
503——服务不可用
再列举下大致不同范围状态的意义
1xx——指示信息,表示请求已接收,继续处理
2xx——成功,表示请求已被成功接收、理解、接受
3xx——重定向,要完成请求必须进行更进一步的操作
4xx——客户端错误,请求有语法错误或请求无法实现
5xx——服务器端错误,服务器未能实现合法的请求
请求/响应头部
请求和响应头部也是分析时常用到的
常用的请求头部(部分):
Accept:接收类型,表示浏览器支持的MIME类型(对标服务端返回的Content-Type)
Accept-Encoding:浏览器支持的压缩类型,如gzip等,超出类型不能接收
Content-Type:客户端发送出去实体内容的类型
Cache-Control:指定请求和响应遵循的缓存机制,如no-cache
If-Modified-Since:对应服务端的Last-Modified,用来匹配看文件是否变动,只能精确到1s之内,http1.0中
Expires:缓存控制,在这个时间内不会请求,直接使用缓存,http1.0,而且是服务端时间
Max-age:代表资源在本地缓存多少秒,有效时间内不会请求,而是使用缓存,http1.1中
If-None-Match:对应服务端的ETag,用来匹配文件内容是否改变(非常精确),http1.1中
Cookie:有cookie并且同域访问时会自动带上
Connection:当浏览器与服务器通信时对于长连接如何进行处理,如keep-alive
Host:请求的服务器URL
Origin:最初的请求是从哪里发起的(只会精确到端口),Origin比Referer更尊重隐私
Referer:该页面的来源URL(适用于所有类型的请求,会精确到详细页面地址,csrf拦截常用到这个字段)
User-Agent:用户客户端的一些必要信息,如UA头部等
常用的响应头部(部分):
Access-Control-Allow-Headers: 服务器端允许的请求Headers
Access-Control-Allow-Methods:服务器端允许的请求方法
Access-Control-Allow-Origin:服务器端允许的请求Origin头部(譬如为*)
Content-Type:服务端返回的实体内容的类型
Date:数据从服务器发送的时间
Cache-Control:告诉浏览器或其他客户,什么环境可以安全的缓存文档
Last-Modified:请求资源的最后修改时间
Expires:应该在什么时候认为文档已经过期,从而不再缓存它
Max-age:客户端的本地资源应该缓存多少秒,开启了Cache-Control后有效
ETag:请求变量的实体标签的当前值
Set-Cookie:设置和页面关联的cookie,服务器通过这个头部把cookie传给客户端
Keep-Alive:如果客户端有keep-alive,服务端也会有响应(如timeout=38)
Server:服务器的一些相关信息
一般来说,请求头部和响应头部是匹配分析的。
譬如,请求头部的Accept
要和响应头部的Content-Type
匹配,否则会报错
譬如,跨域请求时,请求头部的Origin
要匹配响应头部的Access-Control-Allow-Origin
,否则会报跨域错误
譬如,在使用缓存时,请求头部的If-Modified-Since
、If-None-Match
分别和响应头部的Last-Modified
、ETag
对应
7.HTTPS
HTTPS = HTTP+加密+认证+完整性保护
它的加密过程是:
1.浏览器请求建立SSL链接,并向服务端发送一个随机数–Client random和客户端支持的加密方法,比如RSA加密,此时是明文传输。
2.服务端从中选出一组加密算法与Hash算法,回复一个随机数–Server random,并将自己的身份信息以证书的形式发回给浏览器(证书里包含了网站地址,非对称加密的公钥,以及证书颁发机构等信息)
3.浏览器收到服务端的证书后:
-验证证书的合法性(颁发机构是否合法,证书中包含的网址是否和正在访问的一样),如果证书信任,则浏览器会显示一个小锁头,否则会有提示
-用户接收证书后(不管信不信任),浏览会生产新的随机数–Premaster
secret,然后证书中的公钥以及指定的加密方法加密`Premaster secret`,发送给服务器。
-利用Client random、Server random和Premaster
secret通过一定的算法生成HTTP链接数据传输的对称加密key-`session key`
-使用约定好的HASH算法计算握手消息,并使用生成的`session key`对消息进行加密,最后将之前生成的所有信息发送给服务端.
4.
服务端收到浏览器的回复
-利用已知的加解密方式与自己的私钥进行解密,获取`Premaster secret`
-和浏览器相同规则生成`session key`
-使用`session key`解密浏览器发来的握手消息,并验证Hash是否与浏览器发来的一致
-使用`session key`加密一段握手消息,发送给浏览器
5.
浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束.
8. http2.0
http2.0不是https,它相当于是http的下一代规范(譬如https的请求可以是http2.0规范的)
然后简述下http2.0与http1.1的显著不同点:
http1.1中,每请求一个资源,都是需要开启一个tcp/ip连接的,所以对应的结果是,每一个资源对应一个tcp/ip请求,由于tcp/ip本身有并发数限制,所以当资源一多,速度就显著慢下来
http2.0中,一个tcp/ip请求可以请求多个资源,也就是说,只要一次tcp/ip请求,就可以请求若干个资源,分割成更小的帧请求,速度明显提升。
所以,如果http2.0全面应用,很多http1.1中的优化方案就无需用到了(譬如打包成精灵图,静态资源多域名拆分等)
然后简述下http2.0的一些特性:
- 多路复用(即一个tcp/ip连接可以请求多个资源)
- 首部压缩(http头部压缩,减少体积)
- 二进制分帧(在应用层跟传送层之间增加了一个二进制分帧层,改进传输性能,实现低延迟和高吞吐量)
- 服务器端推送(服务端可以对客户端的一个请求发出多个响应,可以主动通知客户端)
- 请求优先级(如果流被赋予了优先级,它就会基于这个优先级来处理,由服务器决定需要多少资源来处理该请求。)
9. 跨域
跨域产生的原因,是因为受到同源策略的限制。同源策略指的是协议、域名、端口不相同。这里我将介绍三种跨域的方式:JSONP、CORS(跨域资源共享)、document.domain + iframe。
9.1 JSONP
1. 原理
动态插入script标签(因为script标签不受同源策略的限制),通过插入script标签引入一个js文件,这个js文件加载成功之后会执行我们在url中指定的回调函数,并且会把我们需要的json数据作为参数传入。
2. 实现
(1)原生实现:
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
// 回调函数
function onBack(res)
{
alert(JSON.stringify(res));
}
//服务端返回如下(返回时即执行全局函数):
onBack({"status": true, "user": "admin"})
(2)jquery ajax:
$.ajax({url:'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "onBack", // 自定义回调函数名
data: {}
});
9.2 CORS
1. 原理
服务器在响应头中设置相应的选项,浏览器如果支持这种方法的话就会将这种跨站资源请求视为合法,进而获取资源。
2. 实现
CORS分为简单请求和复杂请求,简单请求指的是:
(1)请求方法是以下三种方法之一:HEAD、GET、POST;
(2)HTTP的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、
Content-Type(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)。
其他情况就是非简单请求了。
- 简单请求
(1)请求头
:
Origin: http://www.domain.com
(2)响应头
:
Access-Control-Allow-Origin: http://www.domain.com
Access-Control-Allow-Credentials: true //`是否允许传送cookie`
Access-Control-Expose-Headers: FooBar //`CORS请求时,只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须指定。`
(3)另外,ajax请求中,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名,还要设置以下内容:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
- 非简单请求
(1)预检请求
:
OPTIONS /cors HTTP/1.1 `OPTIONS请求是用来询问的`
Origin: http://www.domian.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
(2)响应头
:
Access-Control-Allow-Origin: http://www.domain.com
Access-Control-Allow-Methods: GET, POST, PUT `服务器支持的所有跨域请求的方法`
Access-Control-Allow-Headers: X-Custom-Header `服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。`
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000 `指定本次预检请求的有效期,单位为秒`
(3)之后的步骤就同简单请求了
。
这是CORS的整个流程图:
与JSOP的比较:
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。