最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

【HTTP

IT圈 admin 13浏览 0评论

【HTTP

文章目录

  • TCP/IP和UDP:一个数据包的“旅程”
    • 1. IP:把数据包送达目的主机
    • 2. UDP:把数据包送达应用程序
      • UDP优缺点
    • 3. TCP:把数据完整地送达应用程序
      • UDP的问题 丢失 不完整
      • TCP的特点 重传 完整
      • TCP生命周期
    • TCP连接建立(三次握手,四次挥手)
      • 为什么建立连接是三次握手,关闭连接却是四次挥手?
  • HTTP协议优缺点
    • 特点
    • 缺点
  • HTTP版本差异
    • 0.9
    • 1.0
    • 1.1
    • 1.x的版本问题
    • 2.0
      • 头部压缩
      • 多路复用
      • 服务器推送
        • 比1好的地方
      • 二进制分帧
  • HTTP状态码
    • 1xx 信息类
    • 2xx 成功
    • 3xx 重定向
    • 4XX 客户端错误
    • 5XX 服务器错误
  • DNS如何工作
    • 本地服务器递归查询 和 本地DNS服务器迭代查询
    • 负载均衡
    • 为什么用UDP协议作为传输层协议
  • Connection:keep-alive
  • HTTP缓存策略
    • 强缓存
      • Expires
      • Cache-Control
    • 协商缓存
      • Last-Modified
      • ETag
      • 两者对比
    • 总结
  • GET POST区别
    • 缓存角度
    • 参数角度
    • 编码角度
    • 请求角度
    • 应用场景角度
  • OPTION
    • OPTION和HEAD区别
  • URL
  • 队头阻塞
    • 并发连接
    • 域名分片
  • HTTP数据传输
  • HTTPS工作原理
    • 对称加密算法采用协商的密钥对数据加密
    • 非对称加密实现身份认证和密钥协商
    • 步骤(1)
    • 步骤(2)
    • 步骤(3)
    • 步骤(4)
    • 步骤(5)
    • 第三方认证
    • 数字签名作用
    • 总结
  • 短轮询、长轮询和webSocket
    • 短轮询的基本思路:
    • 短轮询优缺点👇
    • 长轮询的基本思路:
    • 长轮询优缺点👇
    • WebSocket
  • 正向代理反向代理
    • 正向代理
    • 反向代理
  • 负载平衡的两种实现方式?
    • 反向代理
    • DNS
  • Cookie
  • 安全
    • 网络监听
    • DNS缓存中毒
    • xss跨站脚本攻击:
    • CSRF跨站请求伪造:
  • 10种跨域方案
    • 同源策略
    • 一、CORS
    • 限制跨域原因
      • 限制不同源的请求
      • 限制dom操作
    • 简单请求
    • 非简单请求
      • node中的一种cors跨域方式
    • 二、正向代理
    • React实现
      • 1.直接在package.json中设置proxy属性
      • 2.通过middleware中间件的方式设置proxy
    • 三、Nginx反向代理(思想了解)
      • 实例代码
    • 四、JSONP(不会)
      • 「流程解析」
      • 「使用示例」
        • 后端实现
        • 普通 js 示例
        • JQuery Ajax 示例
      • 「原理解析」
    • 五、Websocket
      • 前端
      • 后端
    • 六、window.postMessage()
      • 例子
    • 七、document.domain + Iframe
    • 八、window.location.hash + Iframe
      • 实现原理
      • 实现流程
    • 九、window.name + Iframe
    • 十、浏览器开启跨域(终极方案)

TCP/IP和UDP:一个数据包的“旅程”

1. IP:把数据包送达目的主机

数据包要在互联网上进行传输,就要符合网际协议(Internet Protocol,简称IP)标准。互联网上不同的在线设备都有唯一的地址,地址只是一个数字,这和大部分家庭收件地址类似,你只需要知道一个家庭的具体地址,就可以往这个地址发送包裹,这样物流系统就能把物品送到目的地

计算机的地址就称为IP地址,访问任何网站实际上只是你的计算机向另外一台计算机请求信息。

如果要想把一个数据包从主机A发送给主机B,那么在传输之前,数据包上会被附加上主机B的IP地址信息,这样在传输过程中才能正确寻址。额外地,数据包上还会附加上主机A本身的IP地址,有了这些信息主机B才可以回复信息给主机A。这些附加的信息会被装进一个叫IP头的数据结构里。IP头是IP数据包开头的信息,包含IP版本、源IP地址、目标IP地址、生存时间等信息

为了方便理解,我先把网络简单分为三层结构,如下图

下面我们一起来看下一个数据包从主机A到主机B的旅程:
上层将含有“极客时间”的数据包交给网络层;
网络层再将IP头附加到数据包上,组成新的 IP数据包,并交给底层;
底层通过物理网络将数据包传输给主机B;
数据包被传输到主机B的网络层,在这里主机B拆开数据包的IP头信息,并将拆开来的数据部分交给上层;
最终,含有“极客时间”信息的数据包就到达了主机B的上层了

2. UDP:把数据包送达应用程序

IP是非常底层的协议,只负责把数据包传送到对方电脑,但是对方电脑并不知道把数据包交给哪个程序,是交给浏览器还是交给王者荣耀?因此,需要基于IP之上开发能和应用打交道的协议,最常见的是“用户数据包协议(User Datagram Protocol)”,简称UDP。

UDP中一个最重要的信息是端口号,端口号其实就是一个数字,每个想访问网络的程序都需要绑定一个端口号。通过端口号UDP就能把指定的数据包发送给指定的程序了,所以IP通过IP地址信息把数据包发送给指定的电脑,而UDP通过端口号把数据包分发给正确的程序。和IP头一样,端口号会被装进UDP头里面,UDP头再和原始数据包合并组成新的UDP数据包。UDP头中除了目的端口,还有源端口号等信息

为了支持UDP协议,我把前面的三层结构扩充为四层结构,在网络层和上层之间增加了传输层,如下图所示:

下面我们一起来看下一个数据包从主机A旅行到主机B的路线:

  1. 上层将含有“极客时间”的数据包交给传输层;
  2. 传输层会在数据包前面附加上UDP头,组成新的UDP数据包,再将新的UDP数据包交给网络层;
  3. 网络层再将IP头附加到数据包上,组成新的IP数据包,并交给底层;
    数据包被传输到主机B的网络层,在这里主机B拆开IP头信息,并将拆开来的数据部分交给传输层;
  4. 在传输层,数据包中的UDP头会被拆开,并根据UDP中所提供的端口号,把数据部分交给上层的应用程序;
  5. 最终,含有“极客时间”信息的数据包就旅行到了主机B上层应用程序这里

UDP优缺点

在使用UDP发送数据时,有各种因素会导致数据包出错,虽然UDP可以校验数据是否正确,但是对于错误的数据包,UDP并不提供重发机制,只是丢弃当前的包,而且UDP在发送之后也无法知道是否能达到目的地

虽说UDP不能保证数据可靠性,但是传输速度却非常快,所以UDP会应用在一些关注速度、但不那么严格要求数据完整性的领域,如在线视频、互动游戏等

3. TCP:把数据完整地送达应用程序

对于浏览器请求,或者邮件这类要求数据传输可靠性(reliability)的应用,如果使用UDP来传输会存在两个问题:

UDP的问题 丢失 不完整

  • 数据包在传输过程中容易丢失;
  • 大文件会被拆分成很多小的数据包来传输这些小的数据包会经过不同的路由,并在不同的时间到达接收端,而UDP协议并不知道如何组装这些数据包,从而把这些数据包还原成完整的文件

基于这两个问题,我们引入TCP了。TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议
相对于UDP,TCP有下面两个特点:

TCP的特点 重传 完整

对于数据包丢失的情况,TCP提供重传机制;
TCP引入了数据包排序机制,用来保证把乱序的数据包组合成一个完整的文件。
和UDP头一样,TCP头除了包含了目标端口和本机端口号外,还提供了用于排序的序列号,以便接收端通过序号来重排数据包。

下面看看TCP下的单个数据包的传输流程

通过上图你应该可以了解一个数据包是如何通过TCP来传输的。TCP单个数据包的传输流程和UDP流程差不多,不同的地方在于,通过TCP头的信息保证了一块大的数据传输的完整性。

下面我们再看下完整的TCP连接过程,通过这个过程你可以明白TCP是如何保证重传机制和数据包的排序功能的。

从下图可以看出,一个完整的TCP连接的生命周期包括了“建立连接”“传输数据”和“断开连接”三个阶段。

TCP生命周期

  • 首先,建立连接阶段。这个阶段是通过“三次握手”来建立客户端和服务器之间的连接。TCP 提供面向连接的通信传输。面向连接是指在数据通信开始之前先做好两端之间的准备工作。所谓三次握手,是指在建立一个TCP连接时,客户端和服务器总共要发送三个数据包以确认连接的建立。
  • 其次,传输数据阶段。在该阶段,接收端需要对每个数据包进行确认操作,也就是接收端在接收到数据包之后,需要发送确认数据包给发送端。所以当发送端发送了一个数据包之后,在规定时间内没有接收到接收端反馈的确认消息,则判断为数据包丢失,并触发发送端的重发机制。同样,一个大的文件在传输过程中会被拆分成很多小的数据包,这些数据包到达接收端后,接收端会按照TCP头中的序号为其排序,从而保证组成完整的数据。
  • 最后,断开连接阶段。数据传输完毕之后,就要终止连接了,涉及到最后一个阶段“四次挥手”来保证双方都能断开连接
    到这里你应该就明白了,TCP为了保证数据传输的可靠性,牺牲了数据包的传输速度,因为“三次握手”和“数据包校验机制”等把传输过程中的数据包的数量提高了一倍。

TCP连接建立(三次握手,四次挥手)

TCP(Transmission Control Protocol)传输控制协议
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)
第一次握手(A向B请求建立联机):主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1就知道A要求建立联机;
第二次握手(B向A请求确认联机):主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1随机产生seq=7654321的包;
第三次握手(A向B回复确认联机的情况):主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功

为什么建立连接是三次握手,关闭连接却是四次挥手?

三次握手最主要的原因是要确认双方都有发生和接收数据的能力,如果没有第三次握手的话,就只能保证客户端一般是浏览器有发送的能力,但是不能保证它有接收的能力。

而关闭连接时,服务器收到对方的 FIN 报文时,仅代表对方不再发送数据了但是还能接收数据,而自己未必全部数据都发送给对方了,所以自己可以立即关闭,也可以发送一些数据给对方后,再发送 FIN 报文给对方来表示同意现在关闭连接,因此,己方 ACK 和 FIN 一般都会分开发送,从而导致多了一次。

HTTP协议优缺点

超文本传输协议。

特点

  1. 可拓展:可以传输任意数据
  2. 请求-应答模式
  3. 可靠传输:基于TCP/IP,超时重传
  4. 无状态:没有客户端和服务器在某次会话中产生的数据,在没有状态的http协议下,服务器也一定会保留你每次网络请求对数据的修改,但这跟保留每次访问的数据是不一样的,保留的只是会话产生的结果,而没有保留会话。节约网络开销,比如直播

缺点

  1. 无状态:导致不能保持连接,不能保存信息,购物系统这种就不行。
  2. 明文传输:协议报文用的是文本形式,有暴露。
  3. 队头阻塞:共用一个tcp连接,如果过长要阻塞。

HTTP版本差异

0.9

只有一个GET

1.0

  • 可以传输其他文件
  • GET POST HEAD
  • 加入了头部信息
  • header中的 If-Modified-Since 和 Expires 作为缓存失效的标准
  • 不支持断点重传,每次只会传送全部页面和数据
  • 每台计算机只能绑定一个IP,所以请求消息中的 URL 并没有传递主机名

1.1

  • 长连接,不关闭连接,可被多个请求复用,不用声明Connection: keep-alive。长连接的连接时长可以通过请求头中的 keep-alive 来设置
  • 管道机制:同一个TCP连接里可以同时发多个请求
  • 增加缓存控制标志头来控制缓存失效
  • 支持断点续传,通过使用请求头中的 Range 来实现。
  • 在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。
  • 新增方法:PUT、 PATCH、 OPTIONS、 DELETE。

1.x的版本问题

  • 明文传输不安全
  • 1.1允许复用TCP连接,但是是单道批处理
  • 1.1支持keep-alive,避免创建多次连接,但是会影响服务器的性能

2.0

  • 二进制分帧,头信息帧和数据帧
  • 头部压缩,简化头部
  • 多路复用,在一个连接里可以同时发送多个请求和回应,不用 一一对应,解决队头阻塞
  • 服务器推送 可以主动给客户端发送资源了
  • 请求优先级 可以设置数据帧的优先级 异步处理

头部压缩

传输哈夫曼编码过后的索引序列
(了解大概 之后再补充)

多路复用

1.x 要想实现并发多个请求,必须要开多个TCP连接,浏览器还会对该域名的TCP连接进行限制
2:

  • 同域名通信可以在单个连接上完成
  • 单个连接还有任意数量的双向数据流(全双工)
  • 数据流封装成帧,实现多个帧之间的复用和乱序发送

服务器推送

浏览器发送请求,服务器主动推送与这个请求相关的资源,所以后续就不用请求了

比1好的地方

  • 同域的不同页面资源共享
  • 按照优先级异步推送
  • 有状态 所以可以缓存推送的资源
  • 可以拒收资源

二进制分帧

直接传输二进制,方便机器解码
Headers帧存放头部字段,Data帧存放请求体数据,乱序封装不存在先后关系
可以互相发送帧 双向传输 --》流

HTTP状态码

  • 1xx: 代表请求已被接受,需要继续处理。
  • 2xx: 表示成功状态。
  • 3xx: 重定向状态。
  • 4xx: 客户端错误。
  • 5xx: 服务器端错误。

1xx 信息类

接受的请求正在处理,信息类状态码。

2xx 成功

200 OK 表示从客户端发来的请求在服务器端被正确请求。
204 No content,表示请求成功,但没有资源可返回。
206 Partial Content,该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求 响应报文中包含由 Content-Range 指定范围的实体内容。

3xx 重定向

301 moved permanently,永久性重定向,表示资源已被分配了新的 URL,这时应该按 Location 首部字段提示的 URI 重新保存。
302 found,临时性重定向,表示资源临时被分配了新的 URL。
303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源。
304 not modified,当协商缓存命中时会返回这个状态码。
307 temporary redirect,临时重定向,和302含义相同,不会改变method
当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送 301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做

4XX 客户端错误

400 bad request,请求报文存在语法错误。
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息。
403 forbidden,表示对请求资源的访问被服务器拒绝。
404 not found,表示在服务器上没有找到请求的资源。
405 Method Not Allowed,服务器禁止使用该方法,客户端可以通过options方法来查看服务器允许的访问方法,如下 👇
Access-Control-Allow-Methods →GET,HEAD,PUT,PATCH,POST,DELETE

5XX 服务器错误

500 internal sever error,表示服务器端在执行请求时发生了错误。
502 Bad Gateway,服务器自身是正常的,访问的时候出了问题,具体啥错误我们不知道。
503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求。

DNS如何工作

  • 应用层协议,通常该协议运行在UDP协议之上,使用的是53端口号。

本地服务器递归查询 和 本地DNS服务器迭代查询

本地服务器递归查询
只发一个请求,下一级服务器代发


本地DNS服务器迭代查询
每一级返回查询结果

负载均衡

当用户发起网站域名的 DNS 请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合
在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。
以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。

为什么用UDP协议作为传输层协议

避免使用 TCP 协议时造成的连接时延
为了得到一个域名的 IP 地址,往往会向多个域名服务器查询,如果使用 TCP 协议,那么每次请求都会存在连接时延,这样使 DNS 服务变得很慢。
大多数的地址查询请求,都是浏览器请求页面时发出的,这样会造成网页的等待时间过长。

Connection:keep-alive

用于无状态的HTTP1.x协议,使端到端连接持续有效,避免后续重新建立连接,节约开销

在HTTP/1.0协议中,默认是关闭的,需要在http头加入"Connection: Keep-Alive”,才能启用Keep-Alive;

Connection: keep-alive

http 1.1中默认启用Keep-Alive,存在于请求头中,如果加入"Connection: close “,才关闭。

Connection: close

HTTP缓存策略

强缓存

HTTP1.0版本,使用的是Expires,HTTP1.1使用的是Cache-Control

Expires

Expires即过期时间,时间是相对于服务器的时间而言的,存在于服务端返回的响应头中,在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求。比如下面这样:

Expires:Mon, 29 Jun 2020 11:10:23 GMT 表示该资源在2020年7月29日11:10:23过期,过期时就会重新向服务器发起请求。

这个方式有一个问题:服务器的时间和浏览器的时间可能并不一致,所以HTTP1.1提出新的字段代替它。

Cache-Control

HTTP1.1版本中,使用的就是该字段,这个字段采用的时间是过期时长,对应的是max-age。

Cache-Control:max-age=6000代表该资源返回后6000秒,可以直接使用缓存。

协商缓存

强缓存失效后,浏览器在请求头中携带响应的缓存Tag来向服务器发送请求,服务器根据对应的tag,来决定是否使用缓存。

Last-Modified

表示该缓存最后修改时间

  • 查找请求头中携带If-Modified-Since字段,表示服务器给的范围,如果浏览器缓存时间大于服务器给的范围,就重新请求;
  • 否则返回304not modified,当协商缓存命中时会返回这个状态码,告诉浏览器直接使用缓存。

ETag

服务器给的文档标识,如果有改动,这个标识就会修改
在下一次请求的时候,这个值就作为If-None-Match发给服务器比对

  • 如果这个标识两者一样的话,返回304
  • 否则重新获取新资源

两者对比

性能上,Last-Modified优于ETag,Last-Modified记录的是时间点,而Etag需要根据文件的MD5算法生成对应的hash值。
精度上,ETag优于Last-Modified。ETag按照内容给资源带上标识,能准确感知资源变化,Last-Modified在某些场景并不能准确感知变化,比如👇
编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。

总结

首先检查Cache-Control, 看有无过期,看强缓存是否可用
如果可用的话,直接使用
否则进入协商缓存,发送HTTP请求,服务器通过请求头中的If-Modified-Since或者If-None-Match字段检查资源是否更新
资源更新,返回资源和200状态码。
否则,返回304,直接告诉浏览器直接从缓存中去资源。

GET POST区别

缓存角度

GET 请求后浏览器会主动缓存,POST 默认情况下不能。

参数角度

GET请求一般放在URL中,因此不安全,POST请求放在请求体中,相对而言较为安全,但是在抓包的情况下都是一样的。

编码角度

GET请求只能URL编码,只能接受ASCII码,而POST支持更多的编码类型且不对数据类型限值。

请求角度

GET请求幂等,POST请求不幂等,幂等指发送 M 和 N 次请求(两者不相同且都大于1),服务器上资源的状态一致。
GET请求会一次性发送请求报文,POST请求通常分为两个TCP数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。

应用场景角度

Get 多用于无副作用,幂等的场景,例如搜索关键字。Post 多用于副作用,不幂等的场景,例如注册。

OPTION

  • OPTIONS 请求与 HEAD 类似,一般也是用于客户端查看服务器的性能

  • 这个方法会请求服务器返回该资源所支持的所有 HTTP 请求方法,该方法会用’*'来代替资源名称,向服务器发送 OPTIONS 请求,可以测试服务器功能是否正常。

  • JS 的 XMLHttpRequest对象进行 CORS 跨域资源共享时,对于复杂请求,就是使用 OPTIONS 方法发送嗅探请求,以判断是否有对指定资源的访问权限。

  • 浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

OPTION和HEAD区别

  • HEAD几乎和GET请求一样,只是请求的是HTTP头部,不必传输整个资源内容,就可以得到Request-URI所标识的资源的信息,常用于测试超链接的有效性,是否可以访问,以及最近是否更新
    1、只请求资源的首部;
    2、检查超链接的有效性;
    3、检查网页是否被修改;
    4、多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等

URL

统一资源定位符的简称,Uniform Resource Locator

队头阻塞

一个域名内单道批处理导致的

  • 解决方法

并发连接

允许分配多个长连接,比如http2的多路复用

域名分片

比如TianTian,可以分出很多二级域名,比如Day1.TianTian,Day2.TianTian,Day3.TianTian,这样子就可以有效解决队头阻塞问题。

HTTP数据传输

HTTPS工作原理

我们可以把HTTPS理解成HTTPS = HTTP + SSL(Secure Sockets Layer)/TLS(Transport Layer Security)

TLS/SSL 的功能实现主要依赖于三类基本算法:散列函数 、对称加密和非对称加密,其利用非对称加密实现身份认证和密钥协商对称加密算法采用协商的密钥对数据加密,基于散列函数验证信息的完整性

对称加密算法采用协商的密钥对数据加密

Client客户端和Server端共用一套密钥

非对称加密实现身份认证和密钥协商

  • 有一对秘钥,公钥和私钥。

  • 公钥加密的内容,只有私钥可以解开,私钥加密的内容,所有的公钥都可以解开,这里说的公钥都可以解开,指的是一对秘钥。

  • 公钥可以发送给所有的客户端,私钥只保存在服务器端。

步骤(1)

Client发起一个HTTPS请求,连接443端口。这个过程可以理解成是请求公钥的过程。

步骤(2)

Server端收到请求后,通过第三方机构私钥加密,会把数字证书(也可以认为是公钥证书)发送给Client。

步骤(3)

浏览器安装后会自动带一些权威第三方机构公钥,使用匹配的公钥对数字签名进行解密。
根据签名生成的规则对网站信息进行本地签名生成,然后两者比对。
通过比对两者签名,匹配则说明认证通过,不匹配则获取证书失败。

步骤(4)

在安全拿到服务器公钥后,客户端Client随机生成一个对称密钥,使用服务器公钥(证书的公钥)加密这个对称密钥,发送给Server(服务器)。

步骤(5)

Server(服务器)通过自己的私钥,对信息解密,至此得到了对称密钥,此时两者都拥有了相同的对称密钥。

接下来,就可以通过该对称密钥对传输的信息加密/解密啦,从上面图举个例子👇

Client用户使用该对称密钥加密’明文内容B’,发送给Server(服务器)
Server使用该对称密钥进行解密消息,得到明文内容B。
接下来考虑一个问题,如果公钥被中间人拿到纂改怎么办呢?

客户端可能拿到的公钥是假的,解决办法是什么呢?

第三方认证

客户端无法识别传回公钥是中间人的,还是服务器的,这是问题的根本,我们是不是可以通过某种规范可以让客户端和服务器都遵循某种约定呢?那就是通过第三方认证的方式

在HTTPS中,通过 证书 + 数字签名来解决这个问题。

这里唯一不同的是,假设对网站信息加密的算法是MD5,通过MD5加密后,然后通过第三方机构的私钥再次对其加密,生成数字签名。

这样子的话,数字证书包含有两个特别重要的信息👉某网站公钥+数字签名

我们再次假设中间人截取到服务器的公钥后,去替换成自己的公钥,因为有数字签名的存在,这样子客户端验证发现数字签名不匹配,这样子就防止中间人替换公钥的问题。

那么客户端是如何去对比两者数字签名的呢?

浏览器会去安装一些比较权威的第三方认证机构的公钥,比如VeriSign、Symantec以及GlobalSign等等。
验证数字签名的时候,会直接从本地拿到相应的第三方的公钥,对私钥加密后的数字签名进行解密得到真正的签名。
然后客户端利用签名生成规则进行签名生成,看两个签名是否匹配,如果匹配认证通过,不匹配则获取证书失败。

数字签名作用

数字签名:将网站的信息,通过特定的算法加密,比如MD5,加密之后,再通过服务器的私钥进行加密,形成加密后的数字签名。

第三方认证机构是一个公开的平台,中间人可以去获取。

如果没有数字签名的话,这样子可以就会有下面情况👇

从上面我们知道,如果只是对网站信息进行第三方机构私钥加密的话,还是会受到欺骗。

因为没有认证,所以中间人也向第三方认证机构进行申请,然后拦截后把所有的信息都替换成自己的,客户端仍然可以解密,并且无法判断这是服务器的还是中间人的,最后造成数据泄露。

总结

HTTPS就是使用SSL/TLS协议进行加密传输

  • 大致流程:客户端拿到服务器的公钥(是正确的),然后客户端随机生成一个对称加密的秘钥,使用该公钥加密,传输给服务端,服务端再通过解密拿到该对称秘钥,后续的所有信息都通过该对称秘钥进行加密解密,完成整个HTTPS的流程。
    第三方认证,最重要的是数字签名,避免了获取的公钥是中间人的。

短轮询、长轮询和webSocket

短轮询的基本思路:

浏览器每隔一段时间向浏览器发送 http 请求,服务器端在收到请求后,不论是否有数据更新,都直接进行 响应。
这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。

短轮询优缺点👇

优点是比较简单,易于理解。

缺点是这种方式由于需要不断的建立 http 连接,严重浪费了服务器端和客户端的资源。当用户增加时,服务器端的压力就会变大,这是很不合理的。

长轮询的基本思路:

首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将 这个请求挂起,然后判断服务器端数据是否有更新。

如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。

长轮询优缺点👇

长轮询和短轮询比起来,它的优点是明显减少了很多不必要的 http 请求次数,相比之下节约了资源。

长轮询的缺点在于,连接挂起也会导致资源的浪费。

WebSocket

WebSocket 是 Html5 定义的一个新协议,与传统的 http 协议不同,该协议允许由服务器主动的向客户端推送信息。
使用 WebSocket 协议的缺点是在服务器端的配置比较复杂。WebSocket 是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息。

正向代理反向代理

正向代理

我们常说的代理也就是指正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求

反向代理

这种代理模式下,它隐藏了真实的服务端,当我们向一个网站发起请求的时候,背后可能有成千上万台服务器为我们服务,具体是哪一台,我们不清楚,我们只需要知道反向代理服务器是谁就行,而且反向代理服务器会帮我们把请求转发到真实的服务器那里去,一般而言反向代理服务器一般用来实现负载平衡

负载平衡的两种实现方式?

反向代理

用户的请求都发送到反向代理服务上,然后由反向代理服务器来转发请求到真实的服务器上,以此来实现集群的负载平衡。

DNS

DNS 可以用于在冗余的服务器上实现负载平衡。因为现在一般的大型网站使用多台服务器提供服务,因此一个域名可能会对应多个服务器地址。当用户向网站域名请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。这种方式有一个缺点就是,由于 DNS 服务器中存在缓存,所以有可能一个服务器出现故障后,域名解析仍然返回的是那个 IP 地址,就会造成访问的问题

Cookie

直接上图

安全

网络监听

DNS缓存中毒

xss跨站脚本攻击:

是一种网站应用程序的安全漏洞攻击,是代码注入的一种。常见方式是将恶意代码注入合法代码里隐藏起来,再诱发恶意代码,从而进行各种各样的非法活动
防范:记住一点 “所有用户输入都是不可信的”,所以得做输入过滤和转义

CSRF跨站请求伪造:

也称 XSRF,是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。与 XSS 相比,XSS利用的是用户对指定网站的信任,CSRF利用的是网站对用户网页浏览器的信任。
防范:用户操作验证(验证码),额外验证机制(token使用)等

10种跨域方案

参考链接

同源策略


只有当

  • 「protocol(协议)、domain(域名)、port(端口)三者一致。」
  • 「protocol(协议)、domain(域名)、port(端口)三者一致。」
  • 「protocol(协议)、domain(域名)、port(端口)三者一致。」
  • 在默认情况下 http 可以省略端口 80, https 省略 443

一、CORS

  • 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用准许访问来自不同源服务器上的指定的资源
  • 跨源资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

CORS请求失败会产生错误,但是为了安全,在JavaScript代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

限制跨域原因

限制不同源的请求

限制dom操作

简单请求

  1. 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
  2. HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。都以Access-Control- 开头:

(1)Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

(2)Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

(3)Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

非简单请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

我工作中写的所有页面拉的接口都是非简单请求。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

在页面域名与接口域名不一致的情况下,就出现了每次请求前先发送一个options请求的问题。

OPTIONS请求头信息中,除了Origin字段,还至少会多两个特殊字段:

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。

(2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。

至于其他乱七八糟的字段,现在的我还用不到也不懂,将会慢慢深入了解。

服务器收到预检请求后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示。该字段也可以设为星号,表示同意任意跨源请求。

如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

XMLHttpRequest cannot load
Origin is not allowed by Access-Control-Allow-Origin.

其他字段中Access-Control-Max-Age 用来指定本次预检请求的有效期,单位为秒。该字段可选。

node中的一种cors跨域方式

安装相关中间件

yarn add cors --save
或
npm install cors --save
const express = require('express')
const app = express()
const request = require('request')
const fs = require('fs')
// 跨域.  CROS配置 ---------- Start
const cors = require('cors');app.use(cors({origin: ['http://172.16.136.249:3000'], // 所要允许跨域的ipmethods: ['GET', 'POST'],alloweHeaders: ['Conten-Type', 'Authorization']
}));
// 跨域.  CROS配置 ---------- Endapp.post('/api/getdata', (req, res) => {let data = fs.readFileSync('./data/data.json')console.log('数据', data.toString())res.send(data.toString())
})app.listen(8080, () => {console.log('服务运行成功')
})

二、正向代理

让接口和当前站点同域,也就是说模拟客户端代理服务器进行正向代理

React实现

参考链接

1.直接在package.json中设置proxy属性

本来应该是这样,但是由于proxy只能是字符串,所以就只能进行一次代理

  "proxy": {"/api/**": {"target": "http://172.16.136.249:8080","changeOrigin": true}}

要报错

	"proxy": "http://172.16.136.249:8080"

才是正确的

2.通过middleware中间件的方式设置proxy

用middleware模块

yarn add http-proxy-middleware --save
或
npm install http-proxy-middleware --save

然后

const { createProxyMiddleware } = require('http-proxy-middleware')module.exports = function (app) {app.use(createProxyMiddleware('/api', {target: 'http://172.16.136.249:8080',secure: false,changeOrigin: true,pathRewrite: {"^/api": "/api"}}))
}

三、Nginx反向代理(思想了解)

  • 服务器端进行同域名下path路径的api接口代理,通过path的api隐藏了服务器端口
    步骤:
  1. 配置下hosts 127.0.0.1 local.test
  2. 配置 nginx
server {listen 80;server_name local.test;location /api {proxy_pass http://localhost:8080;}location / {proxy_pass http://localhost:8000;}
}

启动 nginx

sudo nginx

重启 nginx

sudo nginx -s reload

实例代码

前端

后端

四、JSONP(不会)

JSONP 主要就是利用了 script 标签没有跨域限制的这个特性来完成的
仅支持 GET 方法,如果想使用完整的 REST 接口,请使用 CORS 或者其他代理方式。

「流程解析」

1.前端定义解析函数(例如 jsonpCallback=function(){…})
2.通过 params 形式包装请求参数,并且声明执行函数(例如 cb=jsonpCallback)
3.后端获取前端声明的执行函数(jsonpCallback),并以带上参数并调用执行函数的方式传递给前端。

「使用示例」

后端实现

普通 js 示例

JQuery Ajax 示例

「原理解析」

其实这就是 js 的魔法
我们先来看最简单的 js 调用。嗯,很自然的调用。

我们稍稍改造一下,外链的形式。

我们再改造一下,我们把这个外链的 js 就当做是一个动态的接口,因为本身资源和接口一样,是一个请求,也包含各种参数,也可以动态化返回。

五、Websocket

  • websocket套接字意思:客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。就是想模拟全双工咯
  • 没有使用了 HTTP 的响应头, 因此也没有跨域的限制

前端

后端

六、window.postMessage()

  • 该方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。
  • 「window.postMessage()」 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。也就是Windows之间的通信。
  1. 页面和其打开的新窗口的数据传递

  2. 多窗口之间消息传递

  3. 页面与嵌套的 iframe 消息传递

  4. 用法
    详细用法看

otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow: 其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message: 将要发送到其他 window 的数据。
targetOrigin: 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件.
transfer(可选) : 是一串和 message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权

例子


七、document.domain + Iframe

  • 「该方式只能用于二级域名相同的情况下,比如 a.test 和 b.test 适用于该方式」。 只需要给页面添加 document.domain =‘test’ 表示二级域名都相同就可以实现跨域。

八、window.location.hash + Iframe

实现原理

原理就是通过 url 带 hash ,通过一个非跨域的中间页面来传递数据。也是跟Windows有关的

实现流程

一开始 a.html 给 c.html 传一个 hash 值,然后 c.html 收到 hash 值后,再把 hash 值传递给 b.html,最后 b.html 将结果放到 a.html 的 hash 值中。 同样的,a.html 和 b.htm l 是同域的,都是 http://localhost:8000,而 c.html 是http://localhost:8080

九、window.name + Iframe

  • window 对象的 name 属性是一个很特别的属性,当该 window 的 location 变化,然后重新加载,它的 name 属性可以依然保持不变。


  • 通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的 window.name 从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

十、浏览器开启跨域(终极方案)

呃呃 不安全别用哈

【HTTP

文章目录

  • TCP/IP和UDP:一个数据包的“旅程”
    • 1. IP:把数据包送达目的主机
    • 2. UDP:把数据包送达应用程序
      • UDP优缺点
    • 3. TCP:把数据完整地送达应用程序
      • UDP的问题 丢失 不完整
      • TCP的特点 重传 完整
      • TCP生命周期
    • TCP连接建立(三次握手,四次挥手)
      • 为什么建立连接是三次握手,关闭连接却是四次挥手?
  • HTTP协议优缺点
    • 特点
    • 缺点
  • HTTP版本差异
    • 0.9
    • 1.0
    • 1.1
    • 1.x的版本问题
    • 2.0
      • 头部压缩
      • 多路复用
      • 服务器推送
        • 比1好的地方
      • 二进制分帧
  • HTTP状态码
    • 1xx 信息类
    • 2xx 成功
    • 3xx 重定向
    • 4XX 客户端错误
    • 5XX 服务器错误
  • DNS如何工作
    • 本地服务器递归查询 和 本地DNS服务器迭代查询
    • 负载均衡
    • 为什么用UDP协议作为传输层协议
  • Connection:keep-alive
  • HTTP缓存策略
    • 强缓存
      • Expires
      • Cache-Control
    • 协商缓存
      • Last-Modified
      • ETag
      • 两者对比
    • 总结
  • GET POST区别
    • 缓存角度
    • 参数角度
    • 编码角度
    • 请求角度
    • 应用场景角度
  • OPTION
    • OPTION和HEAD区别
  • URL
  • 队头阻塞
    • 并发连接
    • 域名分片
  • HTTP数据传输
  • HTTPS工作原理
    • 对称加密算法采用协商的密钥对数据加密
    • 非对称加密实现身份认证和密钥协商
    • 步骤(1)
    • 步骤(2)
    • 步骤(3)
    • 步骤(4)
    • 步骤(5)
    • 第三方认证
    • 数字签名作用
    • 总结
  • 短轮询、长轮询和webSocket
    • 短轮询的基本思路:
    • 短轮询优缺点👇
    • 长轮询的基本思路:
    • 长轮询优缺点👇
    • WebSocket
  • 正向代理反向代理
    • 正向代理
    • 反向代理
  • 负载平衡的两种实现方式?
    • 反向代理
    • DNS
  • Cookie
  • 安全
    • 网络监听
    • DNS缓存中毒
    • xss跨站脚本攻击:
    • CSRF跨站请求伪造:
  • 10种跨域方案
    • 同源策略
    • 一、CORS
    • 限制跨域原因
      • 限制不同源的请求
      • 限制dom操作
    • 简单请求
    • 非简单请求
      • node中的一种cors跨域方式
    • 二、正向代理
    • React实现
      • 1.直接在package.json中设置proxy属性
      • 2.通过middleware中间件的方式设置proxy
    • 三、Nginx反向代理(思想了解)
      • 实例代码
    • 四、JSONP(不会)
      • 「流程解析」
      • 「使用示例」
        • 后端实现
        • 普通 js 示例
        • JQuery Ajax 示例
      • 「原理解析」
    • 五、Websocket
      • 前端
      • 后端
    • 六、window.postMessage()
      • 例子
    • 七、document.domain + Iframe
    • 八、window.location.hash + Iframe
      • 实现原理
      • 实现流程
    • 九、window.name + Iframe
    • 十、浏览器开启跨域(终极方案)

TCP/IP和UDP:一个数据包的“旅程”

1. IP:把数据包送达目的主机

数据包要在互联网上进行传输,就要符合网际协议(Internet Protocol,简称IP)标准。互联网上不同的在线设备都有唯一的地址,地址只是一个数字,这和大部分家庭收件地址类似,你只需要知道一个家庭的具体地址,就可以往这个地址发送包裹,这样物流系统就能把物品送到目的地

计算机的地址就称为IP地址,访问任何网站实际上只是你的计算机向另外一台计算机请求信息。

如果要想把一个数据包从主机A发送给主机B,那么在传输之前,数据包上会被附加上主机B的IP地址信息,这样在传输过程中才能正确寻址。额外地,数据包上还会附加上主机A本身的IP地址,有了这些信息主机B才可以回复信息给主机A。这些附加的信息会被装进一个叫IP头的数据结构里。IP头是IP数据包开头的信息,包含IP版本、源IP地址、目标IP地址、生存时间等信息

为了方便理解,我先把网络简单分为三层结构,如下图

下面我们一起来看下一个数据包从主机A到主机B的旅程:
上层将含有“极客时间”的数据包交给网络层;
网络层再将IP头附加到数据包上,组成新的 IP数据包,并交给底层;
底层通过物理网络将数据包传输给主机B;
数据包被传输到主机B的网络层,在这里主机B拆开数据包的IP头信息,并将拆开来的数据部分交给上层;
最终,含有“极客时间”信息的数据包就到达了主机B的上层了

2. UDP:把数据包送达应用程序

IP是非常底层的协议,只负责把数据包传送到对方电脑,但是对方电脑并不知道把数据包交给哪个程序,是交给浏览器还是交给王者荣耀?因此,需要基于IP之上开发能和应用打交道的协议,最常见的是“用户数据包协议(User Datagram Protocol)”,简称UDP。

UDP中一个最重要的信息是端口号,端口号其实就是一个数字,每个想访问网络的程序都需要绑定一个端口号。通过端口号UDP就能把指定的数据包发送给指定的程序了,所以IP通过IP地址信息把数据包发送给指定的电脑,而UDP通过端口号把数据包分发给正确的程序。和IP头一样,端口号会被装进UDP头里面,UDP头再和原始数据包合并组成新的UDP数据包。UDP头中除了目的端口,还有源端口号等信息

为了支持UDP协议,我把前面的三层结构扩充为四层结构,在网络层和上层之间增加了传输层,如下图所示:

下面我们一起来看下一个数据包从主机A旅行到主机B的路线:

  1. 上层将含有“极客时间”的数据包交给传输层;
  2. 传输层会在数据包前面附加上UDP头,组成新的UDP数据包,再将新的UDP数据包交给网络层;
  3. 网络层再将IP头附加到数据包上,组成新的IP数据包,并交给底层;
    数据包被传输到主机B的网络层,在这里主机B拆开IP头信息,并将拆开来的数据部分交给传输层;
  4. 在传输层,数据包中的UDP头会被拆开,并根据UDP中所提供的端口号,把数据部分交给上层的应用程序;
  5. 最终,含有“极客时间”信息的数据包就旅行到了主机B上层应用程序这里

UDP优缺点

在使用UDP发送数据时,有各种因素会导致数据包出错,虽然UDP可以校验数据是否正确,但是对于错误的数据包,UDP并不提供重发机制,只是丢弃当前的包,而且UDP在发送之后也无法知道是否能达到目的地

虽说UDP不能保证数据可靠性,但是传输速度却非常快,所以UDP会应用在一些关注速度、但不那么严格要求数据完整性的领域,如在线视频、互动游戏等

3. TCP:把数据完整地送达应用程序

对于浏览器请求,或者邮件这类要求数据传输可靠性(reliability)的应用,如果使用UDP来传输会存在两个问题:

UDP的问题 丢失 不完整

  • 数据包在传输过程中容易丢失;
  • 大文件会被拆分成很多小的数据包来传输这些小的数据包会经过不同的路由,并在不同的时间到达接收端,而UDP协议并不知道如何组装这些数据包,从而把这些数据包还原成完整的文件

基于这两个问题,我们引入TCP了。TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议
相对于UDP,TCP有下面两个特点:

TCP的特点 重传 完整

对于数据包丢失的情况,TCP提供重传机制;
TCP引入了数据包排序机制,用来保证把乱序的数据包组合成一个完整的文件。
和UDP头一样,TCP头除了包含了目标端口和本机端口号外,还提供了用于排序的序列号,以便接收端通过序号来重排数据包。

下面看看TCP下的单个数据包的传输流程

通过上图你应该可以了解一个数据包是如何通过TCP来传输的。TCP单个数据包的传输流程和UDP流程差不多,不同的地方在于,通过TCP头的信息保证了一块大的数据传输的完整性。

下面我们再看下完整的TCP连接过程,通过这个过程你可以明白TCP是如何保证重传机制和数据包的排序功能的。

从下图可以看出,一个完整的TCP连接的生命周期包括了“建立连接”“传输数据”和“断开连接”三个阶段。

TCP生命周期

  • 首先,建立连接阶段。这个阶段是通过“三次握手”来建立客户端和服务器之间的连接。TCP 提供面向连接的通信传输。面向连接是指在数据通信开始之前先做好两端之间的准备工作。所谓三次握手,是指在建立一个TCP连接时,客户端和服务器总共要发送三个数据包以确认连接的建立。
  • 其次,传输数据阶段。在该阶段,接收端需要对每个数据包进行确认操作,也就是接收端在接收到数据包之后,需要发送确认数据包给发送端。所以当发送端发送了一个数据包之后,在规定时间内没有接收到接收端反馈的确认消息,则判断为数据包丢失,并触发发送端的重发机制。同样,一个大的文件在传输过程中会被拆分成很多小的数据包,这些数据包到达接收端后,接收端会按照TCP头中的序号为其排序,从而保证组成完整的数据。
  • 最后,断开连接阶段。数据传输完毕之后,就要终止连接了,涉及到最后一个阶段“四次挥手”来保证双方都能断开连接
    到这里你应该就明白了,TCP为了保证数据传输的可靠性,牺牲了数据包的传输速度,因为“三次握手”和“数据包校验机制”等把传输过程中的数据包的数量提高了一倍。

TCP连接建立(三次握手,四次挥手)

TCP(Transmission Control Protocol)传输控制协议
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)
第一次握手(A向B请求建立联机):主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1就知道A要求建立联机;
第二次握手(B向A请求确认联机):主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1随机产生seq=7654321的包;
第三次握手(A向B回复确认联机的情况):主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功

为什么建立连接是三次握手,关闭连接却是四次挥手?

三次握手最主要的原因是要确认双方都有发生和接收数据的能力,如果没有第三次握手的话,就只能保证客户端一般是浏览器有发送的能力,但是不能保证它有接收的能力。

而关闭连接时,服务器收到对方的 FIN 报文时,仅代表对方不再发送数据了但是还能接收数据,而自己未必全部数据都发送给对方了,所以自己可以立即关闭,也可以发送一些数据给对方后,再发送 FIN 报文给对方来表示同意现在关闭连接,因此,己方 ACK 和 FIN 一般都会分开发送,从而导致多了一次。

HTTP协议优缺点

超文本传输协议。

特点

  1. 可拓展:可以传输任意数据
  2. 请求-应答模式
  3. 可靠传输:基于TCP/IP,超时重传
  4. 无状态:没有客户端和服务器在某次会话中产生的数据,在没有状态的http协议下,服务器也一定会保留你每次网络请求对数据的修改,但这跟保留每次访问的数据是不一样的,保留的只是会话产生的结果,而没有保留会话。节约网络开销,比如直播

缺点

  1. 无状态:导致不能保持连接,不能保存信息,购物系统这种就不行。
  2. 明文传输:协议报文用的是文本形式,有暴露。
  3. 队头阻塞:共用一个tcp连接,如果过长要阻塞。

HTTP版本差异

0.9

只有一个GET

1.0

  • 可以传输其他文件
  • GET POST HEAD
  • 加入了头部信息
  • header中的 If-Modified-Since 和 Expires 作为缓存失效的标准
  • 不支持断点重传,每次只会传送全部页面和数据
  • 每台计算机只能绑定一个IP,所以请求消息中的 URL 并没有传递主机名

1.1

  • 长连接,不关闭连接,可被多个请求复用,不用声明Connection: keep-alive。长连接的连接时长可以通过请求头中的 keep-alive 来设置
  • 管道机制:同一个TCP连接里可以同时发多个请求
  • 增加缓存控制标志头来控制缓存失效
  • 支持断点续传,通过使用请求头中的 Range 来实现。
  • 在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。
  • 新增方法:PUT、 PATCH、 OPTIONS、 DELETE。

1.x的版本问题

  • 明文传输不安全
  • 1.1允许复用TCP连接,但是是单道批处理
  • 1.1支持keep-alive,避免创建多次连接,但是会影响服务器的性能

2.0

  • 二进制分帧,头信息帧和数据帧
  • 头部压缩,简化头部
  • 多路复用,在一个连接里可以同时发送多个请求和回应,不用 一一对应,解决队头阻塞
  • 服务器推送 可以主动给客户端发送资源了
  • 请求优先级 可以设置数据帧的优先级 异步处理

头部压缩

传输哈夫曼编码过后的索引序列
(了解大概 之后再补充)

多路复用

1.x 要想实现并发多个请求,必须要开多个TCP连接,浏览器还会对该域名的TCP连接进行限制
2:

  • 同域名通信可以在单个连接上完成
  • 单个连接还有任意数量的双向数据流(全双工)
  • 数据流封装成帧,实现多个帧之间的复用和乱序发送

服务器推送

浏览器发送请求,服务器主动推送与这个请求相关的资源,所以后续就不用请求了

比1好的地方

  • 同域的不同页面资源共享
  • 按照优先级异步推送
  • 有状态 所以可以缓存推送的资源
  • 可以拒收资源

二进制分帧

直接传输二进制,方便机器解码
Headers帧存放头部字段,Data帧存放请求体数据,乱序封装不存在先后关系
可以互相发送帧 双向传输 --》流

HTTP状态码

  • 1xx: 代表请求已被接受,需要继续处理。
  • 2xx: 表示成功状态。
  • 3xx: 重定向状态。
  • 4xx: 客户端错误。
  • 5xx: 服务器端错误。

1xx 信息类

接受的请求正在处理,信息类状态码。

2xx 成功

200 OK 表示从客户端发来的请求在服务器端被正确请求。
204 No content,表示请求成功,但没有资源可返回。
206 Partial Content,该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求 响应报文中包含由 Content-Range 指定范围的实体内容。

3xx 重定向

301 moved permanently,永久性重定向,表示资源已被分配了新的 URL,这时应该按 Location 首部字段提示的 URI 重新保存。
302 found,临时性重定向,表示资源临时被分配了新的 URL。
303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源。
304 not modified,当协商缓存命中时会返回这个状态码。
307 temporary redirect,临时重定向,和302含义相同,不会改变method
当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送 301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做

4XX 客户端错误

400 bad request,请求报文存在语法错误。
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息。
403 forbidden,表示对请求资源的访问被服务器拒绝。
404 not found,表示在服务器上没有找到请求的资源。
405 Method Not Allowed,服务器禁止使用该方法,客户端可以通过options方法来查看服务器允许的访问方法,如下 👇
Access-Control-Allow-Methods →GET,HEAD,PUT,PATCH,POST,DELETE

5XX 服务器错误

500 internal sever error,表示服务器端在执行请求时发生了错误。
502 Bad Gateway,服务器自身是正常的,访问的时候出了问题,具体啥错误我们不知道。
503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求。

DNS如何工作

  • 应用层协议,通常该协议运行在UDP协议之上,使用的是53端口号。

本地服务器递归查询 和 本地DNS服务器迭代查询

本地服务器递归查询
只发一个请求,下一级服务器代发


本地DNS服务器迭代查询
每一级返回查询结果

负载均衡

当用户发起网站域名的 DNS 请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合
在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。
以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。

为什么用UDP协议作为传输层协议

避免使用 TCP 协议时造成的连接时延
为了得到一个域名的 IP 地址,往往会向多个域名服务器查询,如果使用 TCP 协议,那么每次请求都会存在连接时延,这样使 DNS 服务变得很慢。
大多数的地址查询请求,都是浏览器请求页面时发出的,这样会造成网页的等待时间过长。

Connection:keep-alive

用于无状态的HTTP1.x协议,使端到端连接持续有效,避免后续重新建立连接,节约开销

在HTTP/1.0协议中,默认是关闭的,需要在http头加入"Connection: Keep-Alive”,才能启用Keep-Alive;

Connection: keep-alive

http 1.1中默认启用Keep-Alive,存在于请求头中,如果加入"Connection: close “,才关闭。

Connection: close

HTTP缓存策略

强缓存

HTTP1.0版本,使用的是Expires,HTTP1.1使用的是Cache-Control

Expires

Expires即过期时间,时间是相对于服务器的时间而言的,存在于服务端返回的响应头中,在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求。比如下面这样:

Expires:Mon, 29 Jun 2020 11:10:23 GMT 表示该资源在2020年7月29日11:10:23过期,过期时就会重新向服务器发起请求。

这个方式有一个问题:服务器的时间和浏览器的时间可能并不一致,所以HTTP1.1提出新的字段代替它。

Cache-Control

HTTP1.1版本中,使用的就是该字段,这个字段采用的时间是过期时长,对应的是max-age。

Cache-Control:max-age=6000代表该资源返回后6000秒,可以直接使用缓存。

协商缓存

强缓存失效后,浏览器在请求头中携带响应的缓存Tag来向服务器发送请求,服务器根据对应的tag,来决定是否使用缓存。

Last-Modified

表示该缓存最后修改时间

  • 查找请求头中携带If-Modified-Since字段,表示服务器给的范围,如果浏览器缓存时间大于服务器给的范围,就重新请求;
  • 否则返回304not modified,当协商缓存命中时会返回这个状态码,告诉浏览器直接使用缓存。

ETag

服务器给的文档标识,如果有改动,这个标识就会修改
在下一次请求的时候,这个值就作为If-None-Match发给服务器比对

  • 如果这个标识两者一样的话,返回304
  • 否则重新获取新资源

两者对比

性能上,Last-Modified优于ETag,Last-Modified记录的是时间点,而Etag需要根据文件的MD5算法生成对应的hash值。
精度上,ETag优于Last-Modified。ETag按照内容给资源带上标识,能准确感知资源变化,Last-Modified在某些场景并不能准确感知变化,比如👇
编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。

总结

首先检查Cache-Control, 看有无过期,看强缓存是否可用
如果可用的话,直接使用
否则进入协商缓存,发送HTTP请求,服务器通过请求头中的If-Modified-Since或者If-None-Match字段检查资源是否更新
资源更新,返回资源和200状态码。
否则,返回304,直接告诉浏览器直接从缓存中去资源。

GET POST区别

缓存角度

GET 请求后浏览器会主动缓存,POST 默认情况下不能。

参数角度

GET请求一般放在URL中,因此不安全,POST请求放在请求体中,相对而言较为安全,但是在抓包的情况下都是一样的。

编码角度

GET请求只能URL编码,只能接受ASCII码,而POST支持更多的编码类型且不对数据类型限值。

请求角度

GET请求幂等,POST请求不幂等,幂等指发送 M 和 N 次请求(两者不相同且都大于1),服务器上资源的状态一致。
GET请求会一次性发送请求报文,POST请求通常分为两个TCP数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。

应用场景角度

Get 多用于无副作用,幂等的场景,例如搜索关键字。Post 多用于副作用,不幂等的场景,例如注册。

OPTION

  • OPTIONS 请求与 HEAD 类似,一般也是用于客户端查看服务器的性能

  • 这个方法会请求服务器返回该资源所支持的所有 HTTP 请求方法,该方法会用’*'来代替资源名称,向服务器发送 OPTIONS 请求,可以测试服务器功能是否正常。

  • JS 的 XMLHttpRequest对象进行 CORS 跨域资源共享时,对于复杂请求,就是使用 OPTIONS 方法发送嗅探请求,以判断是否有对指定资源的访问权限。

  • 浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

OPTION和HEAD区别

  • HEAD几乎和GET请求一样,只是请求的是HTTP头部,不必传输整个资源内容,就可以得到Request-URI所标识的资源的信息,常用于测试超链接的有效性,是否可以访问,以及最近是否更新
    1、只请求资源的首部;
    2、检查超链接的有效性;
    3、检查网页是否被修改;
    4、多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等

URL

统一资源定位符的简称,Uniform Resource Locator

队头阻塞

一个域名内单道批处理导致的

  • 解决方法

并发连接

允许分配多个长连接,比如http2的多路复用

域名分片

比如TianTian,可以分出很多二级域名,比如Day1.TianTian,Day2.TianTian,Day3.TianTian,这样子就可以有效解决队头阻塞问题。

HTTP数据传输

HTTPS工作原理

我们可以把HTTPS理解成HTTPS = HTTP + SSL(Secure Sockets Layer)/TLS(Transport Layer Security)

TLS/SSL 的功能实现主要依赖于三类基本算法:散列函数 、对称加密和非对称加密,其利用非对称加密实现身份认证和密钥协商对称加密算法采用协商的密钥对数据加密,基于散列函数验证信息的完整性

对称加密算法采用协商的密钥对数据加密

Client客户端和Server端共用一套密钥

非对称加密实现身份认证和密钥协商

  • 有一对秘钥,公钥和私钥。

  • 公钥加密的内容,只有私钥可以解开,私钥加密的内容,所有的公钥都可以解开,这里说的公钥都可以解开,指的是一对秘钥。

  • 公钥可以发送给所有的客户端,私钥只保存在服务器端。

步骤(1)

Client发起一个HTTPS请求,连接443端口。这个过程可以理解成是请求公钥的过程。

步骤(2)

Server端收到请求后,通过第三方机构私钥加密,会把数字证书(也可以认为是公钥证书)发送给Client。

步骤(3)

浏览器安装后会自动带一些权威第三方机构公钥,使用匹配的公钥对数字签名进行解密。
根据签名生成的规则对网站信息进行本地签名生成,然后两者比对。
通过比对两者签名,匹配则说明认证通过,不匹配则获取证书失败。

步骤(4)

在安全拿到服务器公钥后,客户端Client随机生成一个对称密钥,使用服务器公钥(证书的公钥)加密这个对称密钥,发送给Server(服务器)。

步骤(5)

Server(服务器)通过自己的私钥,对信息解密,至此得到了对称密钥,此时两者都拥有了相同的对称密钥。

接下来,就可以通过该对称密钥对传输的信息加密/解密啦,从上面图举个例子👇

Client用户使用该对称密钥加密’明文内容B’,发送给Server(服务器)
Server使用该对称密钥进行解密消息,得到明文内容B。
接下来考虑一个问题,如果公钥被中间人拿到纂改怎么办呢?

客户端可能拿到的公钥是假的,解决办法是什么呢?

第三方认证

客户端无法识别传回公钥是中间人的,还是服务器的,这是问题的根本,我们是不是可以通过某种规范可以让客户端和服务器都遵循某种约定呢?那就是通过第三方认证的方式

在HTTPS中,通过 证书 + 数字签名来解决这个问题。

这里唯一不同的是,假设对网站信息加密的算法是MD5,通过MD5加密后,然后通过第三方机构的私钥再次对其加密,生成数字签名。

这样子的话,数字证书包含有两个特别重要的信息👉某网站公钥+数字签名

我们再次假设中间人截取到服务器的公钥后,去替换成自己的公钥,因为有数字签名的存在,这样子客户端验证发现数字签名不匹配,这样子就防止中间人替换公钥的问题。

那么客户端是如何去对比两者数字签名的呢?

浏览器会去安装一些比较权威的第三方认证机构的公钥,比如VeriSign、Symantec以及GlobalSign等等。
验证数字签名的时候,会直接从本地拿到相应的第三方的公钥,对私钥加密后的数字签名进行解密得到真正的签名。
然后客户端利用签名生成规则进行签名生成,看两个签名是否匹配,如果匹配认证通过,不匹配则获取证书失败。

数字签名作用

数字签名:将网站的信息,通过特定的算法加密,比如MD5,加密之后,再通过服务器的私钥进行加密,形成加密后的数字签名。

第三方认证机构是一个公开的平台,中间人可以去获取。

如果没有数字签名的话,这样子可以就会有下面情况👇

从上面我们知道,如果只是对网站信息进行第三方机构私钥加密的话,还是会受到欺骗。

因为没有认证,所以中间人也向第三方认证机构进行申请,然后拦截后把所有的信息都替换成自己的,客户端仍然可以解密,并且无法判断这是服务器的还是中间人的,最后造成数据泄露。

总结

HTTPS就是使用SSL/TLS协议进行加密传输

  • 大致流程:客户端拿到服务器的公钥(是正确的),然后客户端随机生成一个对称加密的秘钥,使用该公钥加密,传输给服务端,服务端再通过解密拿到该对称秘钥,后续的所有信息都通过该对称秘钥进行加密解密,完成整个HTTPS的流程。
    第三方认证,最重要的是数字签名,避免了获取的公钥是中间人的。

短轮询、长轮询和webSocket

短轮询的基本思路:

浏览器每隔一段时间向浏览器发送 http 请求,服务器端在收到请求后,不论是否有数据更新,都直接进行 响应。
这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。

短轮询优缺点👇

优点是比较简单,易于理解。

缺点是这种方式由于需要不断的建立 http 连接,严重浪费了服务器端和客户端的资源。当用户增加时,服务器端的压力就会变大,这是很不合理的。

长轮询的基本思路:

首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将 这个请求挂起,然后判断服务器端数据是否有更新。

如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。

长轮询优缺点👇

长轮询和短轮询比起来,它的优点是明显减少了很多不必要的 http 请求次数,相比之下节约了资源。

长轮询的缺点在于,连接挂起也会导致资源的浪费。

WebSocket

WebSocket 是 Html5 定义的一个新协议,与传统的 http 协议不同,该协议允许由服务器主动的向客户端推送信息。
使用 WebSocket 协议的缺点是在服务器端的配置比较复杂。WebSocket 是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息。

正向代理反向代理

正向代理

我们常说的代理也就是指正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求

反向代理

这种代理模式下,它隐藏了真实的服务端,当我们向一个网站发起请求的时候,背后可能有成千上万台服务器为我们服务,具体是哪一台,我们不清楚,我们只需要知道反向代理服务器是谁就行,而且反向代理服务器会帮我们把请求转发到真实的服务器那里去,一般而言反向代理服务器一般用来实现负载平衡

负载平衡的两种实现方式?

反向代理

用户的请求都发送到反向代理服务上,然后由反向代理服务器来转发请求到真实的服务器上,以此来实现集群的负载平衡。

DNS

DNS 可以用于在冗余的服务器上实现负载平衡。因为现在一般的大型网站使用多台服务器提供服务,因此一个域名可能会对应多个服务器地址。当用户向网站域名请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。这种方式有一个缺点就是,由于 DNS 服务器中存在缓存,所以有可能一个服务器出现故障后,域名解析仍然返回的是那个 IP 地址,就会造成访问的问题

Cookie

直接上图

安全

网络监听

DNS缓存中毒

xss跨站脚本攻击:

是一种网站应用程序的安全漏洞攻击,是代码注入的一种。常见方式是将恶意代码注入合法代码里隐藏起来,再诱发恶意代码,从而进行各种各样的非法活动
防范:记住一点 “所有用户输入都是不可信的”,所以得做输入过滤和转义

CSRF跨站请求伪造:

也称 XSRF,是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。与 XSS 相比,XSS利用的是用户对指定网站的信任,CSRF利用的是网站对用户网页浏览器的信任。
防范:用户操作验证(验证码),额外验证机制(token使用)等

10种跨域方案

参考链接

同源策略


只有当

  • 「protocol(协议)、domain(域名)、port(端口)三者一致。」
  • 「protocol(协议)、domain(域名)、port(端口)三者一致。」
  • 「protocol(协议)、domain(域名)、port(端口)三者一致。」
  • 在默认情况下 http 可以省略端口 80, https 省略 443

一、CORS

  • 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用准许访问来自不同源服务器上的指定的资源
  • 跨源资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

CORS请求失败会产生错误,但是为了安全,在JavaScript代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

限制跨域原因

限制不同源的请求

限制dom操作

简单请求

  1. 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
  2. HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。都以Access-Control- 开头:

(1)Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

(2)Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

(3)Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

非简单请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

我工作中写的所有页面拉的接口都是非简单请求。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

在页面域名与接口域名不一致的情况下,就出现了每次请求前先发送一个options请求的问题。

OPTIONS请求头信息中,除了Origin字段,还至少会多两个特殊字段:

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。

(2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。

至于其他乱七八糟的字段,现在的我还用不到也不懂,将会慢慢深入了解。

服务器收到预检请求后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示。该字段也可以设为星号,表示同意任意跨源请求。

如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

XMLHttpRequest cannot load
Origin is not allowed by Access-Control-Allow-Origin.

其他字段中Access-Control-Max-Age 用来指定本次预检请求的有效期,单位为秒。该字段可选。

node中的一种cors跨域方式

安装相关中间件

yarn add cors --save
或
npm install cors --save
const express = require('express')
const app = express()
const request = require('request')
const fs = require('fs')
// 跨域.  CROS配置 ---------- Start
const cors = require('cors');app.use(cors({origin: ['http://172.16.136.249:3000'], // 所要允许跨域的ipmethods: ['GET', 'POST'],alloweHeaders: ['Conten-Type', 'Authorization']
}));
// 跨域.  CROS配置 ---------- Endapp.post('/api/getdata', (req, res) => {let data = fs.readFileSync('./data/data.json')console.log('数据', data.toString())res.send(data.toString())
})app.listen(8080, () => {console.log('服务运行成功')
})

二、正向代理

让接口和当前站点同域,也就是说模拟客户端代理服务器进行正向代理

React实现

参考链接

1.直接在package.json中设置proxy属性

本来应该是这样,但是由于proxy只能是字符串,所以就只能进行一次代理

  "proxy": {"/api/**": {"target": "http://172.16.136.249:8080","changeOrigin": true}}

要报错

	"proxy": "http://172.16.136.249:8080"

才是正确的

2.通过middleware中间件的方式设置proxy

用middleware模块

yarn add http-proxy-middleware --save
或
npm install http-proxy-middleware --save

然后

const { createProxyMiddleware } = require('http-proxy-middleware')module.exports = function (app) {app.use(createProxyMiddleware('/api', {target: 'http://172.16.136.249:8080',secure: false,changeOrigin: true,pathRewrite: {"^/api": "/api"}}))
}

三、Nginx反向代理(思想了解)

  • 服务器端进行同域名下path路径的api接口代理,通过path的api隐藏了服务器端口
    步骤:
  1. 配置下hosts 127.0.0.1 local.test
  2. 配置 nginx
server {listen 80;server_name local.test;location /api {proxy_pass http://localhost:8080;}location / {proxy_pass http://localhost:8000;}
}

启动 nginx

sudo nginx

重启 nginx

sudo nginx -s reload

实例代码

前端

后端

四、JSONP(不会)

JSONP 主要就是利用了 script 标签没有跨域限制的这个特性来完成的
仅支持 GET 方法,如果想使用完整的 REST 接口,请使用 CORS 或者其他代理方式。

「流程解析」

1.前端定义解析函数(例如 jsonpCallback=function(){…})
2.通过 params 形式包装请求参数,并且声明执行函数(例如 cb=jsonpCallback)
3.后端获取前端声明的执行函数(jsonpCallback),并以带上参数并调用执行函数的方式传递给前端。

「使用示例」

后端实现

普通 js 示例

JQuery Ajax 示例

「原理解析」

其实这就是 js 的魔法
我们先来看最简单的 js 调用。嗯,很自然的调用。

我们稍稍改造一下,外链的形式。

我们再改造一下,我们把这个外链的 js 就当做是一个动态的接口,因为本身资源和接口一样,是一个请求,也包含各种参数,也可以动态化返回。

五、Websocket

  • websocket套接字意思:客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。就是想模拟全双工咯
  • 没有使用了 HTTP 的响应头, 因此也没有跨域的限制

前端

后端

六、window.postMessage()

  • 该方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。
  • 「window.postMessage()」 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。也就是Windows之间的通信。
  1. 页面和其打开的新窗口的数据传递

  2. 多窗口之间消息传递

  3. 页面与嵌套的 iframe 消息传递

  4. 用法
    详细用法看

otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow: 其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message: 将要发送到其他 window 的数据。
targetOrigin: 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件.
transfer(可选) : 是一串和 message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权

例子


七、document.domain + Iframe

  • 「该方式只能用于二级域名相同的情况下,比如 a.test 和 b.test 适用于该方式」。 只需要给页面添加 document.domain =‘test’ 表示二级域名都相同就可以实现跨域。

八、window.location.hash + Iframe

实现原理

原理就是通过 url 带 hash ,通过一个非跨域的中间页面来传递数据。也是跟Windows有关的

实现流程

一开始 a.html 给 c.html 传一个 hash 值,然后 c.html 收到 hash 值后,再把 hash 值传递给 b.html,最后 b.html 将结果放到 a.html 的 hash 值中。 同样的,a.html 和 b.htm l 是同域的,都是 http://localhost:8000,而 c.html 是http://localhost:8080

九、window.name + Iframe

  • window 对象的 name 属性是一个很特别的属性,当该 window 的 location 变化,然后重新加载,它的 name 属性可以依然保持不变。


  • 通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的 window.name 从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

十、浏览器开启跨域(终极方案)

呃呃 不安全别用哈

发布评论

评论列表 (0)

  1. 暂无评论