本篇博客仅以个人学习记录使用
HTTP协议概述(HTTP协议为应答模式协议)
HTTP协议是WWW服务器和用户请求代理(例如浏览器等)之间通过应答请求模式传输超文本(例如HTML文件、JavaScript文件、CSS文件、图片甚至服务器接口数据等)内容的一种协议,协议的详细规范序号为RFC2616。
浏览器(用户请求代理)向服务器发送请求时头部中包含请求的方法GET、URL、协议版本号、请求头域字段(如请求接收类型Accept)、缓存控制Cache-control、浏览器Cookie和user-agent信息等,同时也可能会带上请求的正文内容。服务器接收请求处理后也是以一段响应报文作为返回,响应的内容包括HTTP消息响应的协议版本1.1/2、返回码304及返回描述Not Modified、缓存控制信息Cache-control以及正文的HTML内容等,当然如果返回码为304时请求响应返回的正文为空,浏览器将从本地缓存中读取文件。浏览器接收到服务器的返回后会进行解析,同时进行相应的操作,例如将服务器返回正文中的HTML内容装载至浏览器进行解析渲染,或是将服务器返回的JSON字符串解析成前端可用的JSON对象等。
通常一个完整的 HTTP报文由头部、空行、正文三部分组成。空行用于区分报文头部和报文正文,由一个回车符和一个行符组成。请求头通常由请求类型、请求URL、协议版本和扩展内容组成;请求头中还包含其他请求头部域信息,如Accept、Cookie、Cache-Control、Host等;请求正文可以携带浏览器端请求的内容,如POST、PUT请求的表单内容。响应返回报文的格式与此类似,响应报文头部由状态码,状态描述、协议版本、扩展内容组成;响应头包含响应头部域信息,如Date、Contont-Type、Cache-Control、Expires等;服务器返回给浏览器的信息可以放在报文正文部分。
HTTP1.1
长连接
HTTP1.1的长连接机制是通过请求头中keep-alive头域信息来控制的。HTTP1.0默认请求的服务器返回是没有keep-alive的,但在HTTP1.0中,如果要建立长连接,也可以在请求消息中包含Connection:keep-alive头域信息,如果服务器能识别这条连接得到的头域信息,则会在响应消息头域中也包含一个Connection:keep-alive返回,表示后面的文化请求可以复用之前得连接传输。但是在HTTP1.1协议中,任何HTTP请求的报文头部域都会默认包含
keep-alive。keep-alive的控制可以让客户端到服务器端之间的连接在一段时间内持续有效,当一个请求文件的传输连接建立以后,在服务器保持该连接的这段时间内,其他文件请求可以复用这个已经建立好的连接,而不用像HTTP1.0那样重新握手建立连接,这样就有效将建立和关闭连接的完网络开销平均到多个文件的请求上。但是需要注意的是,长连接的请求机制并不会节省传输内容的网络开销。
协议扩展切换
协议扩展切换是指,HTTP1.1协议支持在请求头部域消息中包含Upgrade头并让客户端通过头部标识令服务器知道它能够支持其他备用通信协议的一种
机制,服务器根据客户端请求的其他协议进行切换,切换后使用备用协议与客户端进行通信。例如WebSocket协议就是典型的应用,WebSocket协议通信是通过HTTP的方式建立的,通信连接建立完成后通知服务器切换到WebSocket协议来完成后面的数据通信。
WebSocket协议的连接建立过程:浏览器(假设用户使用的浏览器支持WebSocket)向服务器发送请求,并在消息头中添加Connection:Upgrade和Upgrade:websocket告诉服务器后面需要进行协议切换,切换成为WebSocket协议进行通信,如果服务端支持WebSocket服务并允许该客户端来连接,则可以在响应报文头中返回Upgrade和Connection消息头域,同意浏览器使用WebSocket来连接,同时返回的状态码为101表示请求还需要完成协议的切换
缓存控制
在HTTP1.1版本之前,浏览器缓存主要是通过对HTTP1.0的Expires头部控制来实现的,我们知道Expires只能根据绝对时间来刷新缓存内容,HTTP1.1增加了Cache-Control头域,可以支持max-age用来表示相对过期时间,另外请求服务器时也可以根据Etag和Last-Modified来判断是否从浏览器端缓存中加载文件,此时缓存的控制和判断将决定服务器的响应报文中头部内容的状态码是200还是304.下面来描述一下浏览器发送HTTP请求时进行缓存
读取判断的流程:
1.浏览器会先查询Cache-Control(这里用Expires判断也是可以的,但是Expires一般设置的是绝对过期时间,在HTTP1.1之前较为通用,Cache-Control设置的是相对过期时间,HTTP1.1后推荐使用Cache-Control来控制,如果两者都设置了,则只有Cache-Control的设置生效)来判断内容是否过期,如果未过期,则直接读取浏览器端缓存文件,不发送HTTP请求,否则进入下一步。
2.在浏览器端判断上次文件返回头中是否含有Etag信息,有则带上If-None-Match字段信息发送请求给服务器,服务端判断Etag未修改则返回304,如果修改则返回200,否则进入下一步。
3.在浏览器端判断上次文件返回头中是否含有Last-Modified信息,有则带上If-Modified-Since字段信息发送请求,服务端判断Last-Modified失效则返回200,有效则返回304。
4.如果Etag和Last-Modified都不存在,则直接向服务器请求内容。
以上步骤就是Cache-Control、Etag和Last-Modified控制请求缓存的主要过程。
部分内容传输优化
部分内容传输优化是指HTTP可以支持超文本文件的部分传输,例如,他允许请求一个文件的起始位置和一个偏移长度来进行文件内容的部分传输。
另外HTTP1.1请求允许携带一些数据参数信息一起发送到服务器,请求时的数据信息可以放在请求头(例如,GET、DELETE方法请求时)或正文(例如,POST、PUT方法请求时)中。HTTP请求在消息的正文中除了可以携带文本内容,也可以传输二进制数据,例如表单中使用formData提交上传文件时携带的就是二进制数据。
1 | HTTP报文的头部域信息内容其实有很多,每个头部域字段的控制都具有自己的逻辑和判断机制,以下是常见的一些头部域字段的设置。 |
HTTP2
对比HTTP1.x的优点
HTTP2完全采用二进制的格式来传输数据,而非HTTP1.x的默认文本格式。而二进制在网络中传输的基本单位一般为帧(Frame,一个帧可以理解为具有固定格式和长度的二进制数据包),每个镇包含几个固定部分内容;类型Type、长度Length、标记Flags、流标识Stream和Frame payload(帧有效载荷,一帧能携带的内容数据长度)。多个帧的传输在网络中就形成了帧的传输网络流,所以我们也可以理解为HTTP2协议是通过流式传输的,最大限度地节省了传输带宽。相比于HTTP1.x每次请求都会携带大量冗余头信息(例如浏览器cookie信息等),HTTP2就具有很大的优势了
HTTP2使用TCP多路复用的方式来降低网络请求连接建立和关闭的开销,多个请求可以通过一个TCP连接来完成。HTTP1.1虽然可以通过PipeLine实现并发请求,但是PipeLine是通过串行传输的,多个请求之间的响应可能会被阻塞。
1 | 这里明确的说一下TCP连接复用和HTTP1.1中keep-alive连接复用的区别;TCP复用传输是发生在传输层的,而keep-alive控制的文件的连接复用是在应用层的 |
HTTP2支持传输流的优先级和流量控制机制。HTTP2中每个文件传输流都有自己的传输优先级,并可以通过服务器来动态改变,服务器会保证优先级高的文件流先传输。例如在浏览器渲染中,服务器端就可以优先传输CSS文件来保证页面的渲染,然后在CSS文件全部传输完成后加载js脚本文件。其实这就和我们现在前端的一些优化规则有点相背离,例如使用HTTP2的情况下CSS文件就不一定要写在HTML的顶部,js也不一定要在HTML最底部写了,因为HTTP2的服务器自动就能帮你做好这件事了。
支持服务端推送。服务端能够在特定条件下把资源主动推送给客户端。就像浏览器端的资源预加载一样,例如资源推送可以在HTML文档下载之前让HTML的jshuoCSS文件预先进行下载,从而大大缩短页面加载渲染的等待时间。
所以基于这些HTTP2的优势特性,有人说,以往网站的一些优化规则将不再适用,其实两者也不完全是矛盾的。一方面,适用HTTP2会极大程度上提高网络的传输效率,让我们可以更少的关注页面的性能优化,是对现在开发优化手段的一个增强。另一个方面,现有的优化规则依然能对前端资源的加载和执行起到进一步优化的作用。
HTTPS协议通信过程
HTTPS协议是通过加入SSL(Secure Sockets Layer)层来加密HTTP数据进行安全传输额HTTP协议,同时启用默认的443端口进行数据传输。
HTTPS协议相比较于HTTP协议的请求报文区别不大,HTTPS在请求的头部域字段多了upgrade-insecure-requests,该头部字段指令很关键,他可以用于让页面打开的后续请求自动从HTTP请求升级到HTTPS请求。否则如果使用HTTPS来加载HTML文件,而HTML中加载的是HTTP链接的资源文件,则会产生Mixed Content 类型的错误,并且无法加载资源。所以添加了这个字段,作用就是让浏览器自动升级后面的请求为https请求,同时我们在服务器端响应头域中也要加入header("Content-Security-Policy:upgrade-insecure-requests")来返回给浏览器,否则浏览器默认安全类型策略会阻塞内容并提示block-all-mixed-content类型的错误。
前端实时协议
在实际的前端应用项目中,除了使用应答模式的HTTP协议进行普通网络资源文件的请求加载外,有时也需要建立浏览器客户端与服务端之间的实时连接进行通信,例如网页实时聊天得到应用场景,这就必须涉及到浏览器端的实时通信协议了。对于那些对实时性要求较高的应用场景,普通的HTTP(S)协议就并不适用。虽然前端可以通过Ajax定时间服务端轮询的方式来持续获取服务端的信息,但是这种方式效率相对较低,目前一般只用来处理浏览器上降级体验的实时场景。包括Ajax的方式在内,目前可用来在前端浏览器上进行实时通信的功能实现方式主要有WebSocket、Poll、Long-poll和DDP协议。
WebSocket通信机制
HTTP1.1的协议就已经支持使用Upgrade头域设置进行协议扩展切换,这样就可以实现从HTTP1.1协议切换到其他通信协议进行通信了。一种很典型的实时通信协议便是WebSocket,WebSocket是浏览器端和服务器端建立实时连接的一种通信协议,可以在服务器和浏览器端建立类似Socket方式的消息通信。
相对于HTTP1.1协议,WebSocket协议的优势是方便服务器和浏览器之间的双向数据实时通信。但我们要明白的是,HTTP2也支持服务端的消息推送,也是可以来适应这一场景的。
Poll(轮询)和 Long-poll(长轮询)
尽管HTML5的WebSocket为我们提供了实现前端实时化的方案,提供的API也很完备。但不幸的是,并非所有浏览器都支持WebSocket协议,在桌面或移动端浏览器应用开发时我们仍不能放心的使用它,这时我们就必须回到校友额HTTP协议上考虑采用Poll(轮询)和Long-Poll(长轮询)的方案来应对实时通信的场景了。
Poll
Poll方案很容易理解,即浏览器采用定时向服务器发送请求轮询的方法不断发送或拉取信息。浏览器每隔一秒向服务器发送一次请求,在一秒内服务器更新的内容在下一次轮询中将被浏览器拉取返回。所以这种方案相对来说实时性较差,而且没有新消息时依然需要不断轮询,比较消耗系统资源。
Long-Poll
HTTP请求可以设置一个较长的Timeout等待时间,这样网络轮询请求就可以维持一段较长的时间后返回结果,这也就是Long-Poll(长轮询)的基本思路。服务器只要在这段长轮询时间内进行响应,请求便会立即返回结果;如果这段时间服务器没有返回,浏览器端将自动响应超时并重新发起一个长轮询请求。相比于Poll,Long-Poll的实现更加节省系统资源,实时性更好,不用持续地定时发送网络请求。Long-poll目前一个很典型的应用场景就是网站通过对应的移动客户端进行扫描二维码登录,即用户使用移动客户端扫描二维码登录网站,成功后桌面浏览器页面自动响应跳转进入一个新的登录后页面。用户打开桌面浏览器页面后会立即发送一个用户登录状态查询的长轮询请求,同时开始使用移动客户端扫描二维码,扫描成功时移动客户端会调用接口改变用户的登陆状态,此时服务器可以不断轮询获取用户登录状态改变通知,一旦检测到用户使用移动客户端扫码登录,就将用户登录状态返回给浏览器的长轮询请求,用户浏览器请求到用户登录状态后完成后面的跳转,前端请求登录状态的轮询就可以使用AJAX来模拟实现。
1 | function _getQrAuth() { |
1 | Web应用中客户端和服务端建立实时通信的方式比较多,包括HTML5提供的WebSocket、Flash实现的WebSocket、XMLHttpRequest轮序长连接、XMLRequest Multipart Streaming、script标签的长时间轮询等。当然也还有一些不常用的方式,就不必多说了 |
前端DDP协议
DDP是一种新型的客户端与服务端的实时通信协议,由于兼容性的原因,目前使用还不广泛。DDP使用JSON的数据格式在客户端和浏览器之间进行数据传输通信,所以对于前端开发者来说使用非常方便。有名的Meteor Web框架的双向实时数据更新机制底层使用的就是DDP,这种协议模式下客户端可向服务端发起远程过程调用,客户端也可以订阅服务端数据,在服务端数据变化时,服务端会向客户端发起通知,触发浏览器响应的操作。当然我们借助DDP模块也可以创建一个简单的DDP协议的服务。
1 | // 引入DDP模块,创建客户端连接器 |
RESTful数据协议规范
REST并不是某一种具体的协议,而是定义了一种网络应用软件之间的架构关系并提出了一套与之对应得到网络之间交互调用的规则。与之类似的例如早期的WebSevice,当然WebSevice现在基本都不用了。而在REST形式的软件应用服务(这里讨论的主要是Web应用服务)中,每个资源都有一个与之对应的URI地址,资源本身都是方法调用的目标,方法列表对所有资源都是一样的,而且这些方法都推荐使用HTTP协议的标准方法,例如GET、POST、PUT、DELETE等。如果一个网络应用软件的设计是按照REST定义的,我们就可以认为它使用的交互调用的方法遵循RESTful规范。