前端需要了解的http知识

2,241 阅读16分钟

http基本概念

http是一个无状态 ,无连接的基于TCP协议的单向应用层协议

一、无连接

无连接即每次链接只处理一个请求,请求和应答后就断开链接

二、无状态

http的每次请求都是独立的,不相关的,协议对事物处理没有记忆功能。 HTTP无状态的特性严重阻碍了这些交互式应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持HTTP状态的技术就应运而生了,一个是Cookie,而另一个则是Session。

HTTP请求报文

HTTP请求报文由3部分组成(报文行+报文头+报文体):

常见的HTTP响应报文头属性

Cache-Control
响应输出到客户端后,服务端通过该报文头属告诉客户端如何控制响应内容的缓存。 常见的取值有private、public、no-cache、max-age,no-store,默认为private。 private: 客户端可以缓存 public: 客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的) max-age=xxx: 缓存的内容将在 xxx 秒后失效 no-cache: 需要使用对比缓存来验证缓存数据 no-store: 所有内容都不会缓存 默认为private,缓存时间为31536000秒(365天)也就是说,在365天内再次请求这条数据,都会直接获取缓存数据库中的数据,直接使用。

ETag
一个代表响应服务端资源(如页面)版本的报文头属性,如果某个服务端资源发生变化了,这个ETag就会相应发生变化。它是Cache-Control的有益补充,可以让客户端“更智能”地处理什么时候要从服务端取资源,什么时候可以直接从缓存中返回响应。

Location
我们在JSP中让页面Redirect到一个某个A页面中,其实是让客户端再发一个请求到A页面,这个需要Redirect到的A页面的URL,其实就是通过响应报文头的Location属性告知客户端的,如下的报文头属性,将使客户端redirect到iteye的首页中: Location: www.iteye.com

Set-Cookie
服务端可以设置客户端的Cookie,其原理就是通过这个响应报文头属性实现的: Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
更多详细见 (一个介绍http的地址)

http code

2XX 成功
200 OK,表示从客户端发来的请求在服务器端被正确处理
204 No content,表示请求成功,但响应报文不含实体的主体部分
205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与 204 响应不同在于要求请求方重置内容
206 Partial Content,进行范围请求
3XX 重定向
301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
302 found,临时性重定向,表示资源临时被分配了新的 URL
303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源
304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况(缓存)
307 temporary redirect,临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求
4XX 客户端错误
400 bad request,请求报文存在语法错误
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
403 forbidden,表示对请求资源的访问被服务器拒绝
404 not found,表示在服务器上没有找到请求的资源
5XX 服务器错误
500 internal sever error,表示服务器端在执行请求时发生了错误
501 Not Implemented,表示服务器不支持当前请求所需要的某个功能
503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求

http method

get

GET方法用于使用给定的URI从给定服务器中检索信息,即从指定资源中请求数据。使用GET方法的请求应该只是检索数据,并且不应对数据产生其他影响。

post

POST方法用于将数据发送到服务器以创建或更新资源,它要求服务器确认请求中包含的内容作为由URI区分的Web资源的另一个下属。 POST请求永远不会被缓存,且对数据长度没有限制;我们无法从浏览器历史记录中查找到POST请求。 在规范的应用场景上说,Get 多用于无副作用,幂等的场景,例如搜索关键字。Post 多用于副作用,不幂等的场景,例如注册。

put

PUT方法用于将数据发送到服务器以创建或更新资源,它可以用上传的内容替换目标资源中的所有当前内容。 它会将包含的元素放在所提供的URI下,如果URI指示的是当前资源,则会被改变。如果URI未指示当前资源,则服务器可以使用该URI创建资源。

delete

DELETE方法用来删除指定的资源,它会删除URI给出的目标资源的所有当前内容。

head

HEAD方法与GET方法相同,但没有响应体,仅传输状态行和标题部分。这对于恢复相应头部编写的元数据非常有用,而无需传输整个内容。

OPTIONS

OPTIONS方法用来描述了目标资源的通信选项,会返回服务器支持预定义URL的HTTP策略。(cors预请求了解一下,阮大神系列http://www.ruanyifeng.com/blog/2016/04/cors.html)

https

HTTP是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。
HTTPS相对于HTTP有哪些不同呢?其实就是在HTTP跟TCP中间加多了一层加密层TLS/SSL。
什么是TLS/SSL?
通俗的讲,TLS、SSL其实是类似的东西,SSL是个加密协议,负责对HTTP的数据进行加密。TLS是SSL的升级版。现在提到HTTPS,加密协议基本指的是TLS。

先来了解一点概念
对称加密:
对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。
非对称加密:
有公钥私钥之分,公钥所有人都可以知道,可以将数据用公钥加密,但是将数据解密必须使用私钥解密,私钥只有分发公钥的一方才知道。

TLS握手流程

由上图可知,先进行TCP的三次握手之后,就开始TLS的三次握手,关于TLS的握手细节
见下图

1、clientHello

发送cipher suites (支持的加密套件列表) 和 random number到服务器

2、serverHello

发送random number, 证书(certificate),选择的cipher suite 到客户端

3、客户端验证证书(验证细节见下文)

从证书中拿到公钥, 生成预主钥(pre master secret),用公钥加密预主钥,传输到服务端

我们也可以来看看阮大神的爱丽丝版
开始加密通信之前,客户端和服务器首先必须建立连接和交换参数,这个过程叫做握手(handshake)。
假定客户端叫做爱丽丝,服务器叫做鲍勃,整个握手过程可以用下图说明。

第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
第三步,爱丽丝确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,发给鲍勃。 第四步,鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret)。
第五步,爱丽丝和鲍勃根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。

结论: 公钥加密对称算法的私钥传到服务端,服务端用私钥解密,这个时候客户端和服务端都拥有同一个对称算法的私钥, 开始加密传输吧。

session 恢复连接

握手阶段用来建立SSL连接。如果出于某种原因,对话中断,就需要重新握手。
这时有两种方法可以恢复原来的session:一种叫做session ID,另一种叫做session ticket。
session ID的思想很简单,就是每一次对话都有一个编号(session ID)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。

session ID是目前所有浏览器都支持的方法,但是它的缺点在于session ID往往只保留在一台服务器上。所以,如果客户端的请求发到另一台服务器,就无法恢复对话。session ticket就是为了解决这个问题而诞生的,目前只有Firefox和Chrome浏览器支持。

客户端如何验证证书的真伪

还是先来了解一点概念

CA 机构

又称为证书认证中心 (Certificate Authority) 中心,是一个负责发放和管理数字证书的第三方权威机构,它负责管理PKI结构下的所有用户(包括各种应用程序)的证书,把用户的公钥和用户的其他信息捆绑在一起,在网上验证用户的身份。CA机构的数字签名使得攻击者不能伪造和篡改证书。

CA根证书:

CA本身有自己的证书,江湖人称“根证书”。这个“根证书”是用来证明CA的身份的,本质是一份普通的数字证书。
浏览器通常会内置大多数主流权威CA的根证书。

证书内容

内容非常多,这里我们需要关注的有几个点:
证书包含了颁发证书的机构的名字 -- CA
证书内容本身的数字签名(用CA私钥加密)
证书持有者的公钥
证书签名用到的hash算法
数字签名与摘要
简单的来说,“摘要”就是对传输的内容,通过hash算法计算出一段固定长度的串(是不是联想到了文章摘要)。然后,在通过CA的私钥对这段摘要进行加密,加密后得到的结果就是“数字签名”。

1、防伪造

这种情况比较简单,对证书进行检查:
证书颁发的机构是伪造的:浏览器不认识,直接认为是危险证书
证书颁发的机构是确实存在的,于是根据CA名,找到对应内置的CA根证书、CA的公钥。
用CA的公钥,对伪造的证书的摘要进行解密,发现解不了。认为是危险证书

2、防篡改

假设代理通过某种途径,拿到XX的证书,然后将证书的公钥偷偷修改成自己的,然后喜滋滋的认为用户要上钩了。然而太单纯了:
检查证书,根据CA名,找到对应的CA根证书,以及CA的公钥。
用CA的公钥,对证书的数字签名进行解密,得到对应的证书摘要AA
根据证书签名使用的hash算法,计算出当前证书的摘要BB
对比AA跟BB,发现不一致--> 判定是危险证书
以上关于https介绍大部分来自于
imweb.io/topic/56d67…
www.ruanyifeng.com/blog/2014/0…

http2.0

在写http2.0之前先看看http1.1的一些特性

http1.1

特点:

长连接:

TCP链接会很慢,因为三次握手、滑动窗口、慢启动等的消耗,尽量减少TCP链接。 长连接即TCP连接默认不关闭,可以被多个请求复用,声明Connection: keep-alive就可以了。客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接 ,但是这只是解决了请求串行,并没有解决并行

管道机制和线头阻塞:

即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。 其实HTTP管道化就是将客户端的FIFO队列移到了服务端。在客户端可以依次发送所有要发送的请求(当然这些请求是在同一个域下的),一 个请求发送完之后,不必等待这个请求的响应被接受到,下一个请求就可以被再次发出。在服务器端维持的FIFO队列,这个队列是按照资源的重要程度排列的。 比如HTML比CSS要先返回,JS,CSS比图片先返回。 如果前面请求的响应花了很长的时间,后面的请求也还是需要等待(被阻塞),这就是线头阻塞

所以这个方案并没有实际解决同一个TCP并发请求的问题。

浏览器限制TCP链接:

在HTTP1.1中,浏览器客户端可以\color{red}{同时创建多个TCP链接,也即可以并发多个请求(注意是并发多个TCP链接,每个TCP带一个请求)},但是在同一时间针对同一域名下的TCP链接有一定数量的限制(一般是6-8个TCP链接)。超过限制数目的请求会被阻塞。 为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS代码、域名分片/发散(domain sharding)等等

spdy协议

SPDY(读作“SPeeDY”)是Google开发的基于TCP的会话层 协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。

定位

将页面加载时间减少50%。
最大限度地减少部署的复杂性。SPDY使用TCP作为传输层,因此无需改变现有的网络设施。
避免网站开发者改动内容。 支持SPDY唯一需要变化的是客户端代理和Web服务器应用程序。

具体技术目标

单个TCP连接支持并发的HTTP请求。
压缩报头和去掉不必要的头部来减少当前HTTP使用的带宽。
定义一个容易实现,在服务器端高效率的协议。通过减少边缘情况、定义易解析的消息格式来减少HTTP的复杂性。
强制使用SSL,让SSL协议在现存的网络设施下有更好的安全性和兼容性。
允许服务器在需要时发起对客户端的连接并推送数据。

http2.0 SPDY的升级版

二进制分帧传输

帧:HTTP2.0通信的最小单位,所有帧都共享一个8字节的首部,其中包含帧的长度、类型、标志、还有一个保留位,并且至少有标识出当前帧所属的流的标识符,帧承载着特定类型的数据,如HTTP首部、负荷、等等。
消息:比帧大的通讯单位,是指逻辑上的HTTP消息,比如请求、响应等。由一个或多个帧组成
流:比消息大的通讯单位。是TCP连接中的一个虚拟通道,可以承载双向的消息。每个流都有一个唯一的整数标识符

在二进制分帧层上,HTTP2.0会将所有传输信息分割为更小的消息和帧,并对它们采用二进制格式的编码将其封装。其中,HTTP1.X中的首部信息header封装到Headers帧中,而request body将被封装到Data帧中。 二进制分帧主要是为下文中的各种特性提供了基础。它能把一个数据划分封装为更小更便捷的数据。首先是在单链接多资源方式中,减少了服务端的链接压力,内存占用更少,链接吞吐量更大。这一点可以结合下文中的多路复用来体会。另一方面,由于TCP链接的减少而使网络拥塞状态得以改善,同时慢启动时间的减少。使拥塞和丢包恢复的速度更快。 HTTP 2.0 中所有加强性能的核心点在于此

多路复用

基于二进制分帧层,HTTP2.0可以在共享TCP链接的基础上同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义,交错发出去,在另一端根据流标识符和首部将他们重新组装起来。
1、可以并行交错的发送请求和响应,这些请求和响应之间互不影响
2、只使用一个链接即可并行发送多个请求和响应
3、消除不必要的延迟,从而减少页面加载的时间
4、不必再为绕过HTTP1.x限制而多做很多工作
5、多路复用完美的解决了线头阻塞问题。

请求优先级

每个流都可以带有一个31bit的优先值:0表示最高优先级;2的31次方-1表示最低优先级。
客户端明确指定优先级,服务端可以根据这个优先级作为交互数据的依据,比如客户端优先设置为.css>.js>.jpg。服务端按此顺序返回结果更加有利于高效利用底层连接,提高用户体验。然而,在使用请求优先级时应注意服务端是否支持请求优先级,是否会引起队首阻塞问题,比如高优先级的慢响应请求会阻塞其他资源的交互。

头部压缩

在 HTTP 1.X 中,我们使用文本的形式传输 header,在 header 携带 cookie 的情况下,可能每次都需要重复传输几百到几千的字节。 在 HTTP 2.0 中,使用了 HPACK 压缩格式对传输的 header 进行编码,减少了 header 的大小。并在两端维护了索引表,用于记录出现过的 header ,后面在传输过程中就可以传输已经记录过的 header 的键名,对端收到数据后就可以通过键名找到对应的值。

服务器推送

在 HTTP 2.0 中,服务端可以在客户端某个请求后,主动推送其他资源。 可以想象以下情况,某些资源客户端是一定会请求的,这时就可以采取服务端 push 的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。当然在浏览器兼容的情况下你也可以使用 prefetch 。