小前端探索 HTTP
首先需要说明的是本人只是一个前端,本文内容是综合各大资料搜索到的信息,进行简单明了的解读和记录,主要是针对前端需要了解到的一些http的知识进行归总。
什么是http?
HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程(当然不是只用于web,只是在浏览器的角度说而已)。客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通迅的格式。
在日常的前端开发里面,我们离不开请求后端的接口获取数据对页面进行渲染,那么可以说前端开发对于http的使用是几乎无时无刻的在使用。那么我们常用的Ajax就是基于http协议进行数据传输和接受的,所以前端开发工程师必须对http有一定程度的了解。
http的特点
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。5、支持B/S及C/S模式。
那么前端对于这些特点,我们需要关注的点有以下几点:
请求方法中,我们一般是使用GET和POST为主,当然如果你想要遵从RESTful API的话就不单单是用GET和POST了,还有PUT、PATCH、DELETE了。
Content-Type是一个修改请求体的数据格式的参数(例如:POST),在前端开发的过程中,我们和不同业务线的后端对接,可能他们接收POST的请求体的接收格式不一样,经常会遇到我为什么我之前提交的方式都可以,换成这个项目为什么后端收不到,那么第一时间可以检查一下提交的数据格式是否是后端接收的格式,一般能解决90%这一类问题。具体的Content-Type类型之后再详细说明。
无状态是一个很大的特点,也是一个很大的缺点,因为有这个特性,所以服务器不需要关注请求这个接口的用户的状态,但是往往实现一些像登录这一类的功能的时候,或者商城的列表页根据用户不同,可以做一些精准化展示数据的时候就很麻烦了,所以才会出现SESSION和COOKIES这两个东西。
补充:
http的请求方式共有8种。
OPTIONS - 返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性
HEAD - 向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。
GET - 向特定的资源发出请求。它本质就是发送一个请求来取得服务器上的某一资源。资源通过一组HTTP头和呈现数据(如HTML文本,或者图片或者视频等)返回给客户端。GET请求中,永远不会包含呈现数据。
POST - 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 Loadrunner中对应POST请求函数:web_submit_data,web_submit_form
PUT - 向指定资源位置上传其最新内容
DELETE - 请求服务器删除Request-URL所标识的资源
TRACE - 回显服务器收到的请求,主要用于测试或诊断
CONNECT - HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
http的基本链接原理
因为http是基于TCP/IP的协议,所以还是要说说这个面试老题,3次握手4次挥手的问题了。
三次握手:
第一次握手:客户端发送了一个带有SYN(建立连接)的Tcp报文到服务器,这个三次握手中的开始。表示客户端想要和服务端建立连接。
第二次握手:服务端接收到客户端的请求,返回客户端报文,这个报文带有SYN(建立连接)和ACK(确认)标志,询问客户端是否准备好。
第三次握手:.客户端再次响应服务端一个ACK(确认),表示我已经准备好。
为什么要3次握手那么麻烦?
当然这个其实作为一个前端不需要关注,因为其实基本没你什么事情,但是了解到这一些基本知识,对于日后排除页面性能的时候,某些指标就是需要了解整个http链接过程了。言归正传,为什么需要三次握手呢?
因为第一次握手的时候,客户端发送了一个请求,之后因为网络原因或者任何原因,客户端断网了或者没有收到服务器回传的ACK确认码,在这种情况下,如果服务器不去接收客户端回传ACK码确认,就开启链接,在这个时候就浪费了服务器的资源了,所以第三次握手就为这样的一种情况设计的,服务器必须确认客户端接收到了ACK码才开启连接。
四次挥手:
第一次握手:客户端发送一个FIN(结束),用来关闭客户到服务端的连接。
第二次握手:服务端收到这个FIN,他发回一个ACK(确认),确认收到序号为收到序号+1,和SYN一样,一个FIN将占用一个序号。
第三次握手:服务端发送一个FIN(结束)到客户端,服务端关闭客户端的连接。
第四次握手:客户端发送ACK(确认)报文确认,并将确认的序号+1,这样关闭完成。
那么为什么关闭一个http请求需要走4次握手呢?
因为服务器收到了客户端的FIN报文请求关闭连接的时候,服务器端很可能并不会立即关闭连接,而是需要等待所有数据都传输完毕后才进行关闭,所以会先回复一个ACK报文告诉客户端收到了FIN报文,当数据都传输完毕了,才使用FIN报文告诉客户端现在可以进行关闭了,客户端回复ACK报文进行确认,彼此才真正关闭连接。因此需要4次握手。
前端工程师需要关注http协议中那些部分
如果大家留意看自己发送的http请求,会发现http请求的有很多信息,对于我们日常开发,我们其实只需要去关注部分的属性即可。
http协议主要组成部分:
状态行 - General
请求头 - Request Headers
响应头 - Respones Headers
状态行
在状态行中我们其实一般来说只需要关注Request Method和Status Code就可以了。
请求头
一般来说前端开发需要关注请求头数据大概如下:
Accept - 客户端喜欢接受的数据类型
Accept-Encoding - 一般我们需要看的值就是gzip,一般我们的资源都会进行gzip
Accept-Language - 客户端支持的语言,按顺序使用
Cache-Control - 浏览器请求资源的缓存设置,no-cache会比较常用,意思就是在使用缓存资源的时候必须先请求服务器进行验证
Pragme - 中间服务器不返还资源标识,为兼容http1.0
Connection - 开启持久链接,默认是keep-alive(http1.1才有哟)
Cookie - 就是将你浏览器中符合cookie的path中的cookie字段组成字符串提交给服务器
Referer - 页面来源,就是跳转进当前页面的上一个页面路径
Content-Type - 告诉服务器提交的数据体是那种格式。
响应头
响应头对于前端来说就十分重要了,无论是js或者css静态资源,或者是接口返回数据,里面的信息都十分重要。
Access-Control-Allow-Credentials - 跨域允许提交cookie
Access-Control-Allow-Methods - 跨域允许提交方式
Access-Control-Allow-Origin - 跨域允许的域名路径(如果你的接口跨域可以检查一下这个哟,一般设置*即可)
Cache-Control - http缓存策略
Connection - 开启持久链接,默认是keep-alive(http1.1才有哟)
Content-Encoding - 一般我们需要看的值就是gzip,一般我们的资源都会进行gzip
Content-Type - 告诉浏览器以何种方式接收数据。
Set-Cookie - 服务器对浏览器设置cookie字段
补充几个属性
Expires - 缓存到期时间
X-Cache - CDN标识,有时候我们看CDN资源是否回源了,可以通过这个标识知道是否命中到CDN
Content-Type类型
一般前端使用的Content-Type的类型有3种:
application/x-www-form-urlencoded - 默认方式,原生ajax,jquery都默认使用这种方式提交,该方式会将请求的json数据格式序列化变成key=value&key=value。
multipart/form-data - 这种方式一般是form表单提交文件必须使用这种方式
application/json - 其实就是不进行序列化,直接以JSON方式提交,个人十分喜欢
content-type属性在request头中是代表以何种数据格式进行提交,response头中是代表浏览器需要以何种方式接收数据以及解析数据。
keep-alive(TCP链接持久化)
在HTTP/1.0里,为了实现client到web-server能支持长连接,必须在HTTP请求头里显示指定Connection:keep-alive。
在HTTP/1.1里,就默认是开启了keep-alive,要关闭keep-alive需要在HTTP请求头里显示指定Connection:close。
如果不开启keep-alive的情况下,那么每一次请求都会重复3次握手,如果开启了的话,在一定时间内(这个时间是服务器配置的)可以复用同一个TCP。从而达到了性能的优化。
版本区别
其实一般我们能看见的http版本可以分为3个:
http1.0
http1.1
http2.0
HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1.1则在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。 主要区别主要体现在:
缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
http2.0为前端带来什么特别明显的变化?
http2.0新特性:
新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。
对于前端来说,最大的体验在于多路复用。在http2.0之前,解决TCP多次握手的唯一方式就是使用长链接Connection: keep-alive,但是其实是有性能问题的。因为使用Connection: keep-alive对于服务器来说,其实是并非使用一个连接去请求多个资源,而是并行的多个链接进行请求,这样其实对于服务器的压力是更大的,更容易造成阻塞。
但是使用http2.0的多路复用的话,就会变成多个请求都是使用同一个TCP链接,和Connection: keep-alive是完全不一样的概念,那是因为http2.0引入了二进制数据帧和流的概念,从而可以实现同一个TCP链接对不同请求乱序传输,到达浏览器重新组装。但是以前我们基于http1.x的前端优化将会有所不同,以前我们为了利用浏览器并行发送请求的特性,可能会将页面依赖的资源分发到不同域名的资源服务器中,从而利用keep-alive和浏览器并行请求的特性去优化页面的资源加载或者合并js或者css尽可能减少资源请求量。但是如果使用了http2.0之后,其实我们就可以资源同一放在一个资源服务器中,利用多路复用的特点去实现资源加载的优化,也可以更大化的拆分页面依赖资源的体积,从而让首屏速度最大化。
以上就是作为一个小前端的我对于日常用到的http的一些信息解读,以及http各版本中的优化进行粗略的记录,如果有不同意见和见解欢迎多多留言交流。
版权声明: 本文为 InfoQ 作者【Lam】的原创文章。
原文链接:【http://xie.infoq.cn/article/978d18accde48caf9cf0fcbb5】。文章转载请联系作者。
评论