HTTP协议优缺点
-
灵活可扩展:主要体现在两方面,一方面是语义上的自由,只规定了基本格式,比如空格分隔单词,换行分隔字段,其他部分没有严格的语法限制,另一个是传输的多样性,可以传输图片、文本、音视频等任意数据;
-
请求-应答模式:一发一收,有来有回
-
可靠传输:HTTP协议基于TCP/IP协议,以此j继承了TCP/IP协议的可靠性,
-
无状态:每次HTTP请求都是独立的,不相关的,默认不需要保留任何信息。
状态码
- 1xx:表示临时响应,需要请求者继续操作
- 101:切换协议,请求者要求服务器切换协议,服务器已确认并准备切换
- 2xx:表示请求成功
- 200:表示服务器成功处理请求
- 202:服务器已接收请求,但尚未处理
- 204:服务器成功处理了请求,但没有返回任何内容
- 206:部分内容,使用场景为 HTTP 分块下载和断点续传,当然也会带上相应的响应头字段
Content-Range
- 3xx:重定向相关
- 301:永久重定向
- 302:临时重定向
- 304:协商缓存命中时会返回此状态码
- 4xx:请求出错
- 400:错误请求,服务器不能理解请求的语法
- 403:服务器拒绝请求
- 404:未找到请求的资源
- 405:请求的方法不被服务器允许
- 406:资源无法满足客户端要求
- 408:服务器等待了太长的事件
- 409:多个请求发生了冲突
- 413:请求体数据过大
- 414:请求行里的URI太大
- 5xx:服务器内部出错
- 500:服务器内部出错,并不知道具体的出错问题
- 501:客户端请求的功能还不支持
- 502:服务器自身正常,但访问的时候出错了,具体出错原因不明
- 503:服务器当前很忙,无法相应请求
- 505:服务器不支持请求的HTTP版本
DNS
DNS提供将主机名和域名转换为IP地址的能力。
请求方法
有哪些请求方法
- GET:用来获取资源
- POST:提交数据
- OPTIONS:获取可对资源实行的请求方法
- PUT:修改数据
- DELETE:删除数据
GET和POST有什么区别
- GET请求会被浏览器主动缓存,而POST默认不会
- GET请求的参数一般放在URL中,而POST请求的参数放在请求体重,适合传输敏感数据
- GET请求是幂等的,即执行相同的操作,结果也是相同的,而POST不是幂等的
- GET请求会将请求报文一次性发送出去,而POST请求会分为两个TCP数据包,首先发送header部分,如果服务器相应100,然后发送body部分。
cookie
概念
cookie是一小段文本信息,伴随着用户的请求在web服务器和浏览器之间传递。
cookie 能在所有网页中记住用户的信息。它以字符串的形式包含信息,并键值对的形式保存的,即key=value
的格式。各个cookie
之间一般是以“;
”分隔。
组成
- name=value对:需要保留的信息的键值对形式,value的长度不超过4k,一个
cookie
最多有20对 - domain:表示cookie绑定的域名
- path:匹配的web路由
- expires:cookie有效期
- secure:为true时,表示cookie只允许在https下传输
- httpOnly:为true时,表示无法通过js设置cookie
TCP协议
TCP标志位,有6种标示:
- SYN(SYN建立联机)
- ACK(acknowledgement 确认)
- PSH(push传送)
- FIN(finish结束)
- RST(reset重置)
- URG(urgent紧急)
- Sequence number(SEQ,顺序号码)
- Acknowledge number(确认号码)
三次握手
-
1、客户端发送SYN=1、初始化序号seq=x报文,客户端处于
SYN_SEND
状态 -
2、服务器接收到客户端的SYN报文后,以自己的SYN报文作为应答即SYN=1,并发送确认号ACK=x+1,同时发送自己的序列号seq=y,此时服务器处在
SYN_RCVD
状态 -
3、客户端接收到服务端SYN报文后,发送确认号ACK=y+1,并发送自己的序列号z(x+1),表示自己已经接收到服务端的SYN报文,此时客户端处在
ESTABLISHED
状态,在服务端接收到客户端的ACK
确认报文后,服务器也切换到ESTABLISHED
状态,双方成功建立连接。
四次挥手
-
1、客户端发送请求关闭报文FIN=1,报文中会指定一个序列号seq=u,此时客户端处在
FIN_WAIT1
的状态。 -
2、服务端收到FIN报文后,会发送ACK报文,把客户端的序列号u+1作为ACK报文的序列号值,表明已经收到客户端报文,此时服务器处于
CLOSR_WAIT
的状态,等待服务器处理完数据后,发送连接释放报文 -
3、服务器处理完数据了,可以断开连接了,此时服务器会发送关闭报文FIN=1,并指定一个序列号seq=w,并携带和上一次发送请求一样的ACK确认标志,此时服务器处在
LAST_ACK
状态,等待客户端确认。 -
4、客户端接收到服务端的关闭报文FIN后,会发送一个ACK确认报文,并将服务端的序列号w+1作为确认报文ACK的序列号,发送给服务端,此时客户端处在
TIME_WAIT
状态,等待一阵子后,服务器和客户端均进入CLOSED
状态,连接正式关闭。
缓存
强缓存
-
Expires
:过期时间,如果设置了过期时间,则浏览器会在过期时间内使用缓存,但是浏览器的时间是可以认为改变的,所以可能导致时间对比出错,缓存失效问题,所以提出了相对过期时间 -
cache-control
:缓存控制,常用有一下几个设置:max-age
:表示缓存可以使用多长时间,是一个相对时间public
:表示相应可以被任何区缓存private
:只针对个人用户,不可被代理服务器缓存no-cache
:可以在本地缓存,可以在代理服务器缓存,但是这个缓存要服务器验证才可以使用,强制客户端总是向服务器发送请求,由服务器判断缓存是否可用,即总是启用协商缓存no-store
:彻底禁用缓存,每次都需要从服务器获取资源
浏览器会优先使用cache-control
协商缓存
Etag/If-None-Match
:Etag
:这个字段是由服务器生成返回给浏览器的,它的值是由文件的索引节点(INode)、文件大小(size)、文件最后修改时间(MTime)进行hash之后得到的If-None-Match
:再次请求该资源时,带上上一次服务器返回的ETag
值
过程:当强缓存过期,浏览器会启用协商缓存,首先判断当前是否存在ETag
,如果存在,则再次向服务器发送请求时,在请求头上加上If-None-Match
一同发送到服务器,服务器比对当前的If-None-Match
与资源相对应的ETag
是否相同,如果相同则说明缓存可用,则返回304,否则返回最新的资源。
Last-Modified/If-Modified-Since
:Last-Modified
:服务器返回的文件最后修改时间If-Modified-Since
:再次请求资源是,带上上一次服务器返回的Last-Modified
值
过程:当资源过期时,如果不存在ETag
而是存在Last-modified
,则再次向服务器发送请求时,在请求头上会带上If-Modified-Since
一同发送给服务器,服务器对比资源最后修改时间和当前客户端发送的If-Modified-Since
这个时间,判断资源是否被修改,如果修改了则返回最新的资源,如果没有修改则返回304,使用缓存。
ETag
的优先级高于Last-Modified
,服务器会优先验证ETag
Last-Modified
是以秒为单位的,所以在资源频繁更改的情况下,Last-Modified
是不安全的,而ETag
可以检查文件大小和文件的唯一索引节点,顾即使修改频繁的资源依然能检测到更改
跨域
概念
浏览器遵循同源政策(scheme(协议)
、host(主机)
和port(端口)
都相同则为同源
)。非同源站点有这样一些限制:
- 不能读取和修改对方的 DOM
- 不读访问对方的 Cookie、IndexDB 和 LocalStorage
- 限制 XMLHttpRequest 请求
当浏览器向目标 URI 发 Ajax 请求时,只要当前 URL 和目标 URL 不同源,则产生跨域,被称为跨域请求
。
CORS
CORS
全称为跨域资源共享,需要浏览器和服务器共同支持,在了解CORS
前,需要先知道什么是简单请求和 非简单请求
-
简单请求
- 请求方法为GET、POST、PUT
- 请求头的取值范围为:Accept、Accept-language、Content-Language、Content-Type(只限制在
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
三个值)
-
非简单请求
- 除简单请求之外的所有请求都是非简单请求
请求发送之后,浏览器会在请求头中添加Origin
字段,用来说明请求来自哪里,服务器拿到请求之后,在回应的头中添加Access-Control-Allow-Origin
字段,如果Origin
的值不在Access-Control-Allow-Origin
字段值的范围内,则会触发跨域,浏览器自动拦截该请求。
所以,对于简单请求来说在返回相应中添加Access-Control-Allow-Origin
为*
或是请求源,便可实现跨域请求。
Access-Control-Allow-Origin: *
不过,在我们平时开发中的请求大都不是简单请求,比如我们常用json的形式发送请求参数,所以请求的Content-Type
就会被设置为application/json
,这就是一个非简单请求。
非简单请求在发送之前会先发送预检请求OPTIONS
,看服务器是否支持对应的请求方法,要想实现跨域请求,需要在相应中添加如下响应头信息。
Access-Control-Allow-Origin
: 指定允许访问该资源的外域 URI,对于携带身份凭证的请求不可使用通配符*Access-Control-Allow-Methods
:指明实际请求所允许使用的 HTTP 方法Access-Control-Allow-Headers
:指明实际请求中允许携带的首部字段Access-Control-Expose-Headers
:指定 XMLHttpRequest的getResponseHeader 可以访问的响应头Access-Control-Max-Age
:指定 preflight (预检)请求的结果能够被缓存多久Access-Control-Allow-Credentials
:这个字段是一个布尔值,表示是否允许发送 Cookie,对于跨域请求,浏览器对这个字段默认值设为false
,而如果需要拿到浏览器的 Cookie,需要添加这个响应头并设为true
, 并且在前端也需要设置withCredentials
属性为true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header,Content-Type
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
jsonp
虽然XMLHttpRequest
对象遵循同源策略,但是script标签的src属性不受同源策略的限制,它可以通过src填写目标地址发出get请求,拿到请求结果,实现跨域,因为jsonp的数据是通过src属性获取的,多以我们无法直接拿到数据,通常情况下都是通过一个全局函数,将数据作为参数传递,实现拿到数据,封装一个jsonp如下:
const jsonp = ({ url, params, callbackName }) => {
const generateURL = () => {
let dataStr = '';
for(let key in params) {
dataStr += `${key}=${params[key]}&`;
}
dataStr += `callback=${callbackName}`;
return `${url}?${dataStr}`;
};
return new Promise((resolve, reject) => {
// 初始化回调函数名称
callbackName = callbackName || Math.random().toString.replace(',', '');
// 创建 script 元素并加入到当前文档中
let scriptEle = document.createElement('script');
scriptEle.src = generateURL();
document.body.appendChild(scriptEle);
// 绑定到 window 上,为了后面调用
window[callbackName] = (data) => {
resolve(data);
// script 执行完了,成为无用元素,需要清除
document.body.removeChild(scriptEle);
}
});
}
和CORS
相比,JSONP 最大的优势在于兼容性好,IE 低版本不能使用 CORS 但可以使用 JSONP,缺点也很明显,请求方法单一,只支持 GET 请求。
代理服务器
跨域问题说到底是浏览器的安全限制,如果脱离了浏览器是不存在跨域问题的,所以我们可以在客户端和服务器之间架设一层代理服务器,负责转发请求,这层代理服务器是与客户端同源的,所以客户端与代理服务器之间是不存在跨域的,而代理服务器再将请求转发给真实的服务器处理(服务器与服务器之间是不存在跨域问题的),接收到结果后返回给客户端,就完美实现了跨域请求,webpack-dev-server
的proxy
就是利用的这一特性进行跨域请求的。
短轮询、长轮询
短轮询:前端设置定时器,间隔请求,后端不做修改
长轮询:前端依然设置定时器间隔请求,而后端在处理该接口时,选择尽可能长的时间保持和客户端连接打开的技术,仅在数据变得可用或达到超时阙值后才提供响应,而不是在给到客户端的新数据可用之前,让每个客户端多次发起重复的请求。
websocket
-
WebSocket 是 Html5 定义的一个新协议,与传统的 http 协议不同,该协议允许由服务器主动的向客户端推送信息。
-
使用 WebSocket 协议的缺点是在服务器端的配置比较复杂。WebSocket 是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息。
HTTPS
在 HTTP 协议的基础上添加一层 SSL/TSL 实现,验证证书的过程使用非对称加密,验证成功后使用对称加密
对称加密:解密速度快
非对称加密:保密性好,但是解密速度比对称加密慢很多
所以https在证书验证成功后使用对称加密的方式进行通信
原理:
1.客户端发情 https 请求
- 服务器返回 SSL证书,其本质是第三方私钥加密的服务器公钥
- 客户端接收到证书后,使用操作系统和浏览器内置的CA公钥去匹配证书,如果能匹配说明是目标网站
- 客户端使用CA公钥去解密内容,拿到浏览器返回的公钥
- 生成随机数,用服务器的公钥加密该随机数,发送到服务端
- 服务端使用私钥解密信息,拿到随机数,即后续加密的对称密钥
- 使用对称密钥加密的密文通信
HTTP2.0
-
二进制分帧
-
头部压缩
-
多路复用
-
服务器推送
-
请求优先级