HTTP

381 阅读13分钟

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协议

image.png

TCP标志位,有6种标示:

  • SYN(SYN建立联机)
  • ACK(acknowledgement 确认)
  • PSH(push传送)
  • FIN(finish结束)
  • RST(reset重置)
  • URG(urgent紧急)
  • Sequence number(SEQ,顺序号码)
  • Acknowledge number(确认号码)

三次握手

image.png

  • 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状态,双方成功建立连接。

四次挥手

image.png

  • 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-urlencodedmultipart/form-datatext/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-serverproxy就是利用的这一特性进行跨域请求的。

短轮询、长轮询

短轮询:前端设置定时器,间隔请求,后端不做修改

长轮询:前端依然设置定时器间隔请求,而后端在处理该接口时,选择尽可能长的时间保持和客户端连接打开的技术,仅在数据变得可用或达到超时阙值后才提供响应,而不是在给到客户端的新数据可用之前,让每个客户端多次发起重复的请求。

websocket

  • WebSocket 是 Html5 定义的一个新协议,与传统的 http 协议不同,该协议允许由服务器主动的向客户端推送信息。

  • 使用 WebSocket 协议的缺点是在服务器端的配置比较复杂。WebSocket 是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息。

HTTPS

在 HTTP 协议的基础上添加一层 SSL/TSL 实现,验证证书的过程使用非对称加密,验证成功后使用对称加密

对称加密:解密速度快

非对称加密:保密性好,但是解密速度比对称加密慢很多

所以https在证书验证成功后使用对称加密的方式进行通信

原理:

1.客户端发情 https 请求

  1. 服务器返回 SSL证书,其本质是第三方私钥加密的服务器公钥
  2. 客户端接收到证书后,使用操作系统和浏览器内置的CA公钥去匹配证书,如果能匹配说明是目标网站
  3. 客户端使用CA公钥去解密内容,拿到浏览器返回的公钥
  4. 生成随机数,用服务器的公钥加密该随机数,发送到服务端
  5. 服务端使用私钥解密信息,拿到随机数,即后续加密的对称密钥
  6. 使用对称密钥加密的密文通信

HTTP2.0

  • 二进制分帧

  • 头部压缩

  • 多路复用

  • 服务器推送

  • 请求优先级