从一个经典问题入手梳理网页请求加载过程

509 阅读41分钟

从URL输入到页面展示发生了什么?真的是一个非常经典的问题了,整个过程涉及到大量计算机网络相关知识的串联,作为0202年的前端,这一块已经是必须掌握的知识啦,最近一直在看这方面的内容,既是复习也是梳理总结,我们一起来从头看一看这个过程🙈🙈🙈

从URL输入到页面展现到底发生了什么?

  • 输入URL
  • DNS 解析: 将域名解析成 IP 地址
  • TCP 连接:TCP 三次握手
  • 发送 HTTP 请求
  • 服务器处理请求并返回 HTTP 报文
  • 浏览器解析渲染页面
  • 断开连接:TCP 四次挥手

URL 统一资源定位符

URL(统一资源定位符)=协议+网络地址(主机+域名+端口号)+资源路径

同源策略

同源=协议+域名+端口
同源策略/SOP是浏览器最核心也最基本的安全功能,如果缺少,很容易受到XSS、CSFR等攻击。

  • 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源(广义)
  • 由浏览器同源策略限制的一类请求场景(狭义)
  • 以下操作具有同源策略的限制:
    • AJAX 请求不能发送。
    • 无法获取DOM元素并进行操作。
    • 无法读取Cookie、LocalStorage 和 IndexDB 。

跨域解决方案

跨域资源共享CORS(W3C标准)!!!

  • 需要浏览器和后端同时支持
  • 普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
  • Access-Control-Allow-Origin :该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求
  • Access-Control-Allow-Credentials: 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。(前端必须在AJAX请求中打开withCredentials属性,xhr.withCredentials = true;)
  • Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

JSONP跨域

  • 通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信(type=jsonp)。
  • 缺点:只支持get请求方式,可能会遭受XSS攻击。
<script>
        // 先定义好回调函数
        function getarticleList(res) {
            console.log(res);
        }
        var script = document.createElement('script');
        script.type = 'text/javascript';
        // 设置接口地址+数据获取成功后的回调函数(handleData)
        script.src = 'http://localhost:3088/articleList&callback=getarticleList';
       document.body.appendChild(script);
</script>

document.domain + iframe 跨域

  • 此方案仅限主域相同,子域不同的跨域应用场景。
  • 实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
  • 缺点:只支持get请求方式
try{document.domain = "111"}catch(e){}

window.name + iframe 跨域

  • iframe标签的跨域能力
  • window.names属性值在文档刷新后依然存在的能力(name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB))
  • 缺点:只支持get请求方式

location.hash + iframe

  • a与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
  • 缺点:只支持get请求方式

postMessage跨域

  • 是为数不多可以跨域操作的window属性之一
  • otherWindow.postMessage(message, targetOrigin, [transfer]);
    • otherWindow:目标对象
    • message: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
    • targetOrigin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
    • transfer(可选):是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
otherWindow.postMessage(message,targetOrigin);
 window.addEventListener('message', function(e) {
        alert('data from neal ---> ' + e.data);
}, false);

WebSocket协议跨域

  • HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯。
  • WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据
  • WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。注意!WebSocket不使用http协议,他们都是基于tcp的。
  • 原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

代理和反向代理

同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。
代理:

  • 数据请求过程:浏览器-》代理服务器-》目标服务器
  • 数据返回过程:目标服务器-》代理服务器-》浏览器

反向代理:

  • 数据请求过程:浏览器-》【反向代理服务器-》处理数据的服务器】
  • 数据返回过程:【处理数据的服务器-》反向代理服务器】-》浏览器

比较

  • 从用途上来讲:
    • 正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率。
    • 反向代理的典型用途是为后端的多台服务器提供负载平衡,或为后端较慢的服务器提供缓冲服务。
  • 从安全性来讲:
    • 正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此你必须采取安全措施以确保仅为经过授权的客户端提供服务。
    • 反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。
  • 从使用方来看:
    • 正向代理是浏览器端进行配置的,与服务器端无关,甚至可以对服务端隐藏。
    • 反向代理是服务器端配置的,对浏览器端是透明的。
  • 简单的对比
    • 使用charles等正向代理方式比较简单,需要掌握的知识点也比较少。但相应的其可配置性较弱,仅适合中小型项目使用。
    • 使用nginx的反向代理则相对复杂一些,需要了解基本的nginx配置。但其可配置性较强,支持URL的正则匹配,设置优先级等,适合复杂的项目使用。

Express中间件代理

同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。
在 Node.js 的轻量级 Web 框架 Express 中,我们只需要安装一个 cors[5] 库并添加此中间件即可配置好跨域问题
通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证
利用node + express + http-proxy-middleware搭建一个proxy服务器

DNS 域名系统

应用层协议
用来记录域名和 IP 地址相互映射的信息
域名解析:在 DNS 上记录一条信息记录,分递归查询和迭代查询两种方式,现一般为迭代查询,DNS主要通过UDP实现。

DNS的优化与应用

DNS缓存

  • DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存(ISP DNS 缓存服务器主要承担了域名的解析工作),根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。

DNS负载均衡(DNS重定向)

  • DNS负载均衡技术的实现原理是在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时, DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问 引导到不同的机器上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。

DNS预解析(DNS Prefetch)

  • 当你浏览网页时,浏览器会在加载网页时对网页中的域名进行解析缓存,这样在你单击当前网页中的连接时就无需进行 DNS 的解析,减少用户等待时间,提高用户体验。
  • 注:dns-prefetch 需慎用,多页面重复DNS预解析会增加重复DNS查询次数。
//用meta信息来告知浏览器, 当前页面要做DNS预解析
<meta http-equiv="x-dns-prefetch-control" content="on" /> 
//在页面header中使用link标签来强制对DNS预解析
<link rel="dns-prefetch" href="https://tieba.baidu.com/" /> 

CDN 内容分发网络

**Content Delivery Network **在用户和服务器间加入中间层CDN,利用DNS的重定向技术,DNS服务器会返回一个跟用户最接近的点的IP地址给用户,CDN节点的服务器负责响应用户的请求,提供所需的内容。

CDN关键技术

  • 缓存算法决定命中率、源服务器压力、POP节点存储能力
  • 分发能力取决于IDC能力和IDC策略性分布
  • 负载均衡(智能调度)决定最佳路由、响应时间、可用性、服务质量
  • 基于DNS的负载均衡以CNAME实现[to cluster],智取最优节点服务
  • 缓存点有客户端浏览器缓存、本地DNS服务器缓存
  • 缓存内容有DNS地址缓存、客户请求内容缓存、动态内容缓存
  • 支持协议如静动态加速(图片加速、https带证书加速)、下载加速、流媒体加速、企业应用加速、手机应用加速

回源

  • 当 cdn 缓存服务器中没有符合客户端要求的资源的时候,缓存服务器会请求上一级缓存服务器,以此类推,直到获取到。最后如果还是没有,就会回到我们自己的服务器去获取资源。
  • 没有资源,资源过期,访问的资源是不缓存资源等都会导致回源。

OSI模型(7层)和TCP/IP模型(4层)

image.png

TCP 传输控制协议

传输层协议,提供了完善的错误控制和流量控制,能够确保数据正常传输,是一个面向连接的协议。

TCP三次握手

  • 客户端发送一个带 SYN=1,Seq=X 的数据包到服务器端口(第一次握手,由浏览器发起,告诉服务器我要发送请求了)
  • 服务器发回一个带 SYN=1, ACK=X+1, Seq=Y 的响应包以示传达确认信息(第二次握手,由服务器发起,告诉浏览器我准备接受了,你赶紧发送吧)
  • 客户端再回传一个带 ACK=Y+1, Seq=Z 的数据包,代表“握手结束”(第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧)

TCP四次挥手

  • 发起方向被动方发送报文,Fin、Ack、Seq,表示已经没有数据传输了。并进入 FIN_WAIT_1 状态。 (第一次挥手:由浏览器发起的,发送给服务器,我请求报文发送完了,你准备关闭吧)
  • 被动方发送报文,Ack、Seq,表示同意关闭请求。此时主机发起方进入 FIN_WAIT_2 状态。 (第二次挥手:由服务器发起的,告诉浏览器,我请求报文接受完了,我准备关闭了,你也准备吧)
  • 被动方向发起方发送报文段,Fin、Ack、Seq,请求关闭连接。并进入 LAST_ACK 状态。 (第三次挥手:由服务器发起,告诉浏览器,我响应报文发送完了,你准备关闭吧)
  • 发起方向被动方发送报文段,Ack、Seq。然后进入等待 TIME_WAIT 状态。被动方收到发起方的报文段以后关闭连接。发起方等待一定时间未收到回复,则正常关闭。 (第四次挥手:由浏览器发起,告诉服务器,我响应报文接受完了,我准备关闭了,你也准备吧)

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

这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送。

UDP 用户数据报协议

传输层协议,只提供了基本的错误检测,是一个无连接的协议。

TCP和UDP的区别是什么

  • TCP(传输控制协议)使用面向连接的通信方式, 在收发数据前,必须和对方建立可靠的连接大大提高了数据通信的可靠性,使发送数据端和接收端在数据正式传输前就有了交互, 为数据正式传输打下了可靠的基础。(TCP包头的最小长度,为20字节)
  • UDP(用户数据报协议)是一个非连接的协议,传输数据之前源端和终端不建立连接, 当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上,一台服务机可同时向多个客户机传输相同的消息(8个字节),使用尽最大努力交付,即不保证可靠交付(ping 是一个UDP)
  • 区别:
    • 基于连接与无连接;
    • 对系统资源的要求(TCP较多,UDP少);
    • UDP程序结构较简单;
    • 流模式与数据报模式 ;
    • TCP保证数据正确性,UDP可能丢包;
    • TCP保证数据顺序,UDP不保证。

HTTP 超文本传输协议

「HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。」

应用层协议

HTTP请求

HTTP请求报文由:请求行、请求头部、空行和请求数据四个部分组成。

  • 请求行:
    • ①是请求方法,GET、POST、DELETE、HEAD、OPTIONS、PUT、TRACE。
    • ②是请求对应的URL地址,它和报文头的Host属性组成完整的请求URL。
    • ③是协议名称及版本号。
  • 请求头:
    • ④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。与缓存相关的规则信息,均包含在header中
  • 请求体:
    • ⑤是报文体,它将一个页面表单中的组件值通过param1=value1&param2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1&param2=value2”的方式传递请求参数。

简单请求

同时满足下列两条要求:

  • 使用GET,HEAD,POST请求方式
  • Content-Type 的值属于text/plain,multipart/form-data,application/x-www-form-urlencoded其中之一

复杂请求

不符合简单请求要求的请求。复杂请求会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

HTTP请求方法

HTTP是基于客户端/服务端(C/S)的架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议,基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。 无连接的,可扩展的,无状态的

  • HTTP1.0定义了三种请求方法:GET, POST , HEAD方法。
  • HTTP1.1新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
  • RESful 接口的话一般会用到 PUT、DELETE、GET、POST(分别对应增删查改)
方法描述
GET通常⽤于请求服务器发送某些资源。
POST向服务器提交数据(如提交表单或上传文件),数据被包含再请求体中。POST可能会导致新的资源建立或已有资源修改。
HEAD请求资源的头部信息,并且这些头部与 HTTP GET ⽅法请求时返回的⼀致。该请求⽅法 的⼀个使⽤场景是在下载⼀个⼤⽂件前先获取其⼤⼩再决定是否要下载,以此可以节约带宽资源。
OPTIONS⽤于获取⽬的资源所⽀持的所有HTTP请求方法,可以测试服务器功能是否正常运作。
PUT从客户端向服务器传送的数据取代制定文档的内容。
PATCH⽤于对资源进⾏部分修改。
DELETE⽤于删除指定的资源。
TRACE回显服务器收到的请求,主要⽤于测试或诊断。
CONNECTHTTP/1.1 协议中预留给能够将连接改为管道⽅式的代理服务器,主要使用SSL和TLS将数据加密后通过网络隧道进行传输。

GET VS POST

  • GET是幂等的,而POST不是
  • GET产生一个TCP数据包;POST产生两个TCP数据包(首先发送的是header部分,若是服务器响应100(continue),则会发送body部分,当然「火狐」浏览器除外,它的 POST 请求只发一个 TCP 包)。
  • GET在浏览器回退时是无害的,而POST会再次提交请求。POST 多次调⽤,可能造成多次提交;GET 不会。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • 数据载体不同,GET参数通过URL传递,POST放在Request body中。GET请求在URL中传送的参数是有长度限制的,而POST没有。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。POST更安全,他的 URL 字符长度不会因为浏览器地址栏字符长度所限制(而 GET,如果参数很多导致字符过长,则会被浏览器截断)。
  • 既然POST要分为两个TCP数据包发送,那GET是不是会比POST更有效啊?
    • 首先,GET和POST都有它们自己的语义的,最好不要混用
    • 另外,虽然说POST会分为两个数据包发送,但是其实在网络条件好的情况下,发一次包和发两次包的相差的时间基本可以被无视了。并且在网络条件差的情况下,两次包的TCP在验证数据包的完整性上还有更大的优点。
    • 再者,也并不是所有的浏览器的POST请求都会发送两次TCP数据包的,比如火狐就不会。

POST VS PUT

  • PUT是幂等的,而POST不是
  • 语义不同,POST ⽤于新增资源、PUT 指向单⼀资源 。
  • POST /article 新增⽂章,PUT /article/1 对 id 是 1 的 article 进⾏修改。

PUT vs PATCH

  • PUT是幂等的,而PATCH不是
  • 都是对单⼀资源的修改。
  • 内容不同 PUT 影响全量内容;PATCH 是修改部分内容(在请求中定义了一个描述修改的实体集合,如果被请求修改的资源不存在的话,服务器就会创建一个新的资源)。

HTTP响应

HTTP响应报文由:状态行、消息报头、空行和响应正文四个部分组成。

  • 响应行:
    • ①报文协议及版本;
    • ②状态码及状态描述;
  • 响应头:
    • ③响应报文头,也是由多个属性组成;
  • 响应体: 
    • ④响应报文体,即我们真正要的“干货”
  • 设置响应头最常用的方法是HttpServletResponse的setHeader,该方法有两个参数,分别表示响应头的名字和值。和设置状态代码相似,设置响应头应该在发送任何文档内容之前进行。HttpServletResponse还提供了许多设置:
    • setContentType:设置Content-Type头。大多数Servlet都要用到这个方法。
    • setContentLength:设置Content-Length头。对于支持持久HTTP连接的浏览器来说,这个函数是很有用的。
    • addCookie:设置一个Cookie(Servlet API中没有setCookie方法,因为应答往往包含多个Set-Cookie头)。

HTTP 响应状态码

分类分类描述
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

常见状态码

状态码状态码英文名称中文描述
100Continue继续。客户端应继续其请求
101Switching Protocols切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
200OK请求成功。一般用于GET与POST请求
201Created已创建。成功请求并创建了新的资源
202Accepted已接受。已经接受请求,但未处理完成
301Moved Permanently永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替(网页更改网址后对搜索引擎友好的最好方法,只要不是暂时搬移的情况,都建议使用301来做转址)
302Found临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI(可能会出现网址“劫持”,尽量不用)
303See Other查看其它地址,与301类似。使用GET请求查看(在文件上传完成后让客户端自动重定向到一个上传成功的结果页面)
304Not Modified未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源(304响应不包含消息体,因此以消息头后的第一个空行结尾)
400Bad Request客户端请求的语法错误,服务器无法理解
401Unauthorized请求要求用户的身份认证
403Forbidden服务器理解请求客户端的请求,但是拒绝执行此请求
404Not Found服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
500Internal Server Error服务器内部错误,无法完成请求
501Not Implemented服务器不支持请求的功能,无法完成请求
502Bad Gateway作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503Service Unavailable由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504Gateway Time-out充当网关或代理的服务器,未及时从远端服务器获取请求
505HTTP Version not supported服务器不支持请求的HTTP协议的版本,无法完成处理

HTTP 部首

  • Accept:告诉WEB服务器自己接受什么介质类型,/ 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type。
  • Accept-Charset: 浏览器申明自己接收的字符集 Accept-Encoding: 浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate) Accept-Language:浏览器申明自己接收的语言 语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等。
  • Accept-Ranges:WEB服务器表明自己是否接受获取其某个实体的一部分(比如文件的一部分)的请求。bytes:表示接受,none:表示不接受。
  • Age:当代理服务器用自己缓存的实体去响应请求时,用该头部表明该实体从产生到现在经过多长时间了。
  • Authorization:当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给WEB服务器。
  • Cache-Control
    • 请求:
      • no-cache(不要缓存的实体,要求现在从WEB服务器去取)
      • max-age:(只接受 Age 值小于 max-age 值,并且没有过期的对象)
      • max-stale:(可以接受过去的对象,但是过期时间必须小于 max-stale 值)
      • min-fresh:(接受其新鲜生命期大于其当前 Age 跟 min-fresh 值之和的缓存对象)
    • 响应:
      • public(可以用 Cached 内容回应任何用户)
      • private(只能用缓存内容回应先前请求该内容的那个用户)
      • no-cache(可以缓存,但是只有在跟WEB服务器验证了其有效后,才能返回给客户端)
      • max-age:(本响应包含的对象的过期时间)
    • ALL: no-store(不允许缓存)
  • Connection:
    • 请求:
      • close(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)。
      • keepalive(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求)。
    • 响应:
      • close(连接已经关闭)。
      • keepalive(连接保持着,在等待本次连接的后续请求)。
      • Keep-Alive:如果浏览器请求保持连接,则该头部表明希望 WEB 服务器保持连接多长时间(秒)。例如:Keep-Alive:300
  • Content-Encoding:WEB服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。例如:Content-Encoding:gzip
  • Content-Language:WEB 服务器告诉浏览器自己响应的对象的语言。
  • Content-Length: WEB 服务器告诉浏览器自己响应的对象的长度。例如:Content-Length: 26012
  • Content-Range: WEB 服务器表明该响应包含的部分对象为整个对象的哪个部分。例如:Content-Range: bytes 21010-47021/47022
  • Content-Type: WEB 服务器告诉浏览器自己响应的对象的类型。例如:Content-Type:application/xml
  • Host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。例如:Host:rss.sina.com.cn
  • Location:WEB 服务器告诉浏览器,试图访问的对象已经被移到别的位置了,到该头部指定的位置去取。例如:Location:i0.sinaimg.cn/dy/deco/200…
  • Pramga:主要使用 Pramga: no-cache,相当于 Cache-Control: no-cache。例如:Pragma:no-cache
  • Proxy-Authenticate: 代理服务器响应浏览器,要求其提供代理身份验证信息。Proxy-Authorization:浏览器响应代理服务器的身份验证请求,提供自己的身份信息。
  • Range:浏览器(比如 Flashget 多线程下载时)告诉 WEB 服务器自己想取对象的哪部分。例如:Range: bytes=1173546-
  • Referer:浏览器向 WEB 服务器表明自己是从哪个 网页/URL 获得/点击 当前请求中的网址/URL。例如:Referer:www.sina.com/
  • Server: WEB 服务器表明自己是什么软件及版本等信息。例如:Server:Apache/2.0.61 (Unix)
  • User-Agent: 浏览器表明自己的身份(是哪种浏览器)。例如:User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14) Gecko/20080404 Firefox/2、0、0、14

HTTP Cookie

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)
  • Secure 和 HttpOnly
    • 标记为 Secure 的Cookie只应通过被HTTPS协议加密过的请求发送给服务端。
    • 为避免跨域脚本 (XSS) 攻击,通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie,它们只应该发送给服务端。

Session,Cookie,localstorege,sessionstorege区别

  • Cookie:数据始终在同源的http请求中携带(即使不需要),在浏览器和服务器间来回传递;Cookie数据还有路径(path)的概念,可以限制Cookie只属于某个路径下。Cookie数据不能超过4k,同时因为每次http请求都会携带Cookie,所以Cookie只适合保存很小的数据,如会话标识。
  • Session: 弥补了 HTTP 无状态特性,服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录。
  • Web storage API (本地存储和会话存储):两者都是仅在客户端(即浏览器)中保存,不参与和服务器的通信,可以达到5M或更大 
    • localStorage - 没有时间限制的数据存储
    • sessionStorage - 针对一个 session 的数据存储,当用户关闭浏览器窗口后,数据会被删除。

HTTP 缓存

Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具有响应性。常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。
浏览器在加载资源时,会先判断是否命中强缓存再验证是命中协商缓存。

强缓存

  • 浏览器如果判断本地缓存未过期,就直接使用,无需发起http请求
  • 查看 header 头中的 Expires(HTTP/1.0,在HTTP/1.1中被摒弃了) 和 Cache-control(HTTP/1.1) 来判断是否满足规则
  • 同时设置 Expire 和 Cache-Control ,Cache-Control 的优先级别更高
Expires:Fri, 27 Oct 2017 07:55:30 GMT //缓存到期时间(绝对时间,单位秒)

Cache-Control:max-age=600 //资源缓存的最大有效时间(相对时间,单位秒)
Cache-Control:no-cache //需要进行协商缓存,发送请求到服务器确认是否使用缓存。
Cache-Control:no-store //禁止使用缓存,每一次都要重新请求数据。
Cache-Control:public //所有内容都将被缓存(客户端和代理服务器都可缓存)
Cache-Control:private //不能被多用户共享,所有内容只有客户端可以缓存,默认取值

协商缓存

  • 浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
  • 当强缓存没有命中,浏览器再次请求数据时,客户端将备份的缓存标识,比如 If-Modify-Since 或 Etag 发送到服务器
  • 服务器根据缓存标识确认资源是否更新,如果资源未更新,请求响应返回的http状态为 **304 **并且会显示一个 Not Modified 的字符串,告诉浏览器使用本地缓存
  • 如果资源已经更新,返回新的数据,将新数据存入缓存。
  • 同时设置Last-Modified 和 Etag ,服务器优先校验 Etag,如果 Etag 相等就会继续比对 Last-Modified,最后才会决定是否返回 304。
  • Etag和Last-Modified对比
    • 精确度上:Etag要优于Last-Modified。
    • 优先级上:服务器校验优先考虑Etag。
    • 性能上:Etag要逊于Last-Modified
//Last-Modified等于If-Modified-Since,说明资源未修改
//问题:周期性变化。如果资源在一个周期内修改回原来的样子了,认为可以使用缓存,但Last-Modified不这样认为。
If-Modified-Since: Fri, 27 Oct 2017 07:55:30 GMT //资源最后修改的时间(绝对时间,单位秒)
Last-Modified: Fri, 27 Oct 2017 07:55:30 GMT //资源最后修改的时间(绝对时间,单位秒)

//Etag等于If-no-match,说明资源未修改
//Etag由文件内容 hash 生成,保证资源的唯一性,资源发生改变Etag就会发生改变
ETag: "Oprbh7deLfM6ygq+XHy882aRMJQ="
If-no-match: "Oprbh7deLfM6ygq+XHy882aRMJQ="

两者共同点:客户端获得的数据最后都是从客户端缓存中获得。  两者的区别:从名字就可以看出,强缓存不与服务器交互,而协商缓存则需要与服务器交互。

HTTP keep-alive

HTTP keep-alive 也称为 HTTP 长连接。它通过重用一个 TCP 连接来发送/接收多个 HTTP请求,来减少创建/关闭多个 TCP 连接的开销(包括响应时间、CPU 资源、减少拥堵等)。
如果客户端和服务端的确需要进行多次通信,则开启 keep-alive 是更好的选择,例如在微服务架构中,通常微服务的使用方和提供方会长期有交流,此时最好开启 keep-alive。

// HTTP/1.0 协议开启 keep-alive
Connection: keep-alive
// HTTP/1.1 协议默认开启 keep-alive,除非显式地关闭它
Connection: close

HTTPS

HTTPS基于HTTP协议,通过SSL或TLS(可以看作SSL3.0)提供加密处理数据、验证对方身份以及数据完整性保护。特点如下:

  • 内容加密:采用混合加密技术,中间者无法直接查看明文内容
  • 验证身份:通过证书认证客户端访问的是自己的服务器
  • 保护数据完整性:防止传输的内容被中间人冒充或者篡改

HTTP与HTTPS比较

  • HTTP超文本,明文,端口80
  • HTTPS,SSL加密在传输层完成,端口443
  • 区别
    • HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。HTTP是超文本传输协议,信息是明文传输。
    • HTTPS 则是具有安全性的SSL加密传输协议。HTTP和HTTPS使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。
    • HTTP的连接很简单,是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比HTTP协议安全。
  • 升级
    • 原本是HTTP直接与TCP通信,变成先和SSL通信,获得证书(包含公钥),后再与TCP通信返回客户端需要到CA机构申请SSL证书,将SSL证书部署到服务器端,就可以实现HTTPS网站。

HTTP/1.0

最早的http只是使用在一些较为简单的网页上和网络请求上,所以比较简单,每次请求都打开一个新的TCP链接,收到响应之后立即断开连接。

HTTP/1.1

  • HTTP/1.1 引入了更多的缓存控制策略,如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等
  • HTTP/1.1 允许范围请求,即在请求头中加入Range头部
  • HTTP/1.1 的请求消息和响应消息都必须包含Host头部,以区分同一个物理主机中的不同虚拟主机的域名
  • HTTP/1.1 默认开启持久连接,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。

缺陷

  • 高延迟,页面加载速度降低
    • 队头阻塞导致带宽无法充分利用:HTTP是基于 请求-响应 的模型,在同一个TCP长连接中,前一个请求没有得到响应,后面的请求就会被阻塞。
  • 无特性状态,巨大的HTTP头部
  • 明文传输,不安全

HTTP/2

高带宽,低延迟

特性

  • 传输内容使用二进制协议(更小的传输体积)
  • 使用作为最小传输单位
  • ** 多路复用**(只通过一个TCP连接)和(一个独立的,双向的帧序列)
  • 头压缩(HPACK算法)
  • 服务器推送(缓存推送,主动推送的资源是能被浏览器缓存的)
  • 优先级与依赖性
  • 可重置
  • 流量控制(只有数据帧会受到流量控制)
  • HTTPS rfc 规范并没有要求 HTTP2 强制使用 TLS,但是目前世界所有浏览器和服务器实现都基于 HTTPS 来实现 HTTP2

HTTP/3

基于 UDP 协议的“QUIC”协议,让HTTP跑在QUIC上而不是TCP上。

浏览器渲染

浏览器模式

  • 标准模式(standards mode)和怪异模式(quirks mode)
    • 怪异模式,浏览器使用自己的方式解析渲染页面,在不同的浏览器就会显示不同的样式(IE盒子)。
    • 标准模式,浏览器使用W3C的标准解析渲染页面(标准盒子)。 
  • 通过 document.compatMode 的值可以知道当前用的是什么模式
    • BackCompat:怪异模式(IE 6以下版本永远定在了怪异模式)
    • CSS1Compat:标准模式
  • 浏览器解析时使用标准模式还是怪异模式,DTD声明()定义了标准文档的类型(标准模式解析)文档类型,会使浏览器使用相关的方式加载网页并显示,忽略DTD声明,将使网页进入怪异模式。

浏览器渲染步骤

  • 解析HTML(深度遍历),构建DOM树
  • 解析CSS,生成CSS规则树(顺序:浏览器默认样式->自定义样式->页面内的样式)
  • 合并DOM树和CSS规则,生成render树(不包含隐藏的节点display)
  • 布局render树(Layout/reflow),负责各元素尺寸、位置的计算
  • 绘制render树(paint),绘制页面像素信息

重绘和重排的区别

  • reflow重排/回流:任一元素几何尺寸(规模尺寸,布局,隐藏等)改变重新布局
  • repaint重绘:任一元素样式属性改变,都重新绘制
  • 何时发生回流:
    • 页面渲染初始化
    • 添加或者删除可见的Dom元素
    • 元素位置发生改变,元素尺寸发生改变
    • 浏览器窗口尺寸改变-resize事件发生
    • 元素字体大小改变,内容改变,比如文本改变或者图片大小改变而影响计算值宽度和高度的改变
    • 获取某些属性(clientWidth,offsetWidth,scrollWidth)或调用某些方法(scrollTo())
    • 激活CSS伪类(例如::hover)
    • 设置 style 属性的值 
  • 回流一定引起重绘,重绘不一定引起回流(代价更高)
  • 优化(减少回流,重排)
    • 浏览器自己的优化
      • 浏览器会维护1个队列,把所有会引起重排,重绘的操作放入这个队列,等队列中的操作到一定数量或者到了一定时间间隔,浏览器就会flush队列,进行一批处理,这样多次重排,重绘变成一次重排重绘
    • CSS
      • 样式集中改变
      • 避免使用table布局
      • 将需要多次重排的元素(如动画),position属性设为absolute或者fixed,这样元素就脱离文档流,变化不会影响其他元素
      • 避免设置多层内联样式
      • 避免使用CSS表达式,例如:calc()(仅 IE 浏览器)
    • JS
      • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性
      • 在内存中多次操作节点,完成后再添加到文档中去。比如,异步获取表格数据,再添加到页面中,我们可以先获取数据,在内存中构建整个表格的html结构,再一次性的添加到文档中去,而不是循环添加(尽量避免使用table布局,一点小的改变都会导致其他节点回流)
      • 由于display属性为none的元素不在渲染树中,对隐藏元素的操作不会引发其它元素的重排。如果要对一个元素进行复杂操作,可以先隐藏,操作完成后再显示。触发两次重排
      • 不要在布局信息改变的时候做查询(会导致渲染队列强制刷新)
      • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来

CSS3硬件加速(GPU加速)

  • 常见的触发硬件加速的css属性
    • transform
    • opacity
    • filters
    • Will-change

  • 优点
    • 使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘
    • 对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。
  • 缺点
    • 如果你为太多元素使用css3硬件加速,会导致内存占用较大,会有性能问题
    • 在GPU渲染字体会导致抗锯齿无效。这是因为GPU和CPU的算法不同。因此如果你不在动画结束的时候关闭硬件加速,会产生字体模糊

浏览器缓存存放

from disk cache 磁盘缓存

不请求网络资源,资源在内存当中,一般脚本、字体、图片会存在内存当中

from memory cache 内存缓存

不请求网络资源,在磁盘当中,一般非脚本会存在内存当中,如css等

用户行为对浏览器缓存的影响

  • 打开网页,地址栏输入地址: 查找 disk cache 中是否有匹配。如有则使用;如没有则发送网络请求。
  • 普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache 是可用的,会被优先使用(如果匹配的话)。其次才是 disk cache。
  • 强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control:no-cache(为了兼容,还带了 Pragma:no-cache),服务器直接返回 200 和最新内容。

WEB安全

XSS(跨站脚本攻击)

是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。
XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。

XSS攻击

可以分为3类:反射型(非持久型)、存储型(持久型)、基于DOM。

  • 存储型 XSS:常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。
  • 反射型 XSS:常见于通过 URL 传递参数的功能,如网站搜索、跳转等。
  • 反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。
  • DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

XSS预防

预防存储型和反射型 XSS 攻击:

  • 改成纯前端渲染,把代码和数据分隔开。
  • 对 HTML 做充分转义。

预防 DOM 型 XSS 攻击:

  • 避免在字符串中拼接不可信数据

其他:

  • Content Security Policy:在服务端使用 HTTP的 Content-Security-Policy 头部来指定策略,或者在前端设置 meta 标签。
  • 输入内容长度控制
  • 输入内容限制
  • HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
  • 验证码:防止脚本冒充用户提交危险操作。

CSRF(跨站请求伪造)

是一种劫持受信任用户向服务器发送非预期请求的攻击方式。通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。

GET类型的CSRF

[](https://awps-assets.meituan.net/mit-x/blog-images-bundle-2018b/ff0cdbee.example/withdraw?amount=10000&for=hacker)
//在受害者访问含有这个img的页面后,浏览器会自动向
//http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker发出一次HTTP请求。
//bank.example就会收到包含受害者登录信息的一次跨域请求。

POST类型的CSRF

<form action="http://bank.example/withdraw" method=POST>
    <input type="hidden" name="account" value="xiaoming" />
    <input type="hidden" name="amount" value="10000" />
    <input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script> 
//访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。

链接类型的CSRF

链接类型的CSRF并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击。
由于之前用户登录了信任的网站A,并且保存登录状态,只要用户主动访问上面的这个PHP页面,则表示攻击成功。

CSRF预防

  • 阻止不明外域的访问
    • 同源检测
    • Samesite Cookie:如果SamesiteCookie被设置为Strict,浏览器在任何跨域请求中都不会携带Cookie,新标签重新打开也不携带,所以说CSRF攻击基本没有机会。(可能替代同源验证的方案)
  • 提交时要求附加本域才能获取的信息
    • 添加验证码(体验不好)
    •  判断请求的来源:检测Referer(并不安全,Referer可以被更改)
    • CSRF Token(主流)
      • 将CSRF Token输出到页面中
      • 页面提交的请求携带这个Token
      • 服务器验证Token是否正确)
    • 双重Cookie验证
      • 在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串(例如csrfcookie=v8g9e4ksfhw)。
      • 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中。
      • 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。

DDOS(分布式拒绝服务)

DDOS 攻击利用目标系统网络服务功能缺陷或者直接消耗其系统资源,使得该目标系统无法提供正常的服务。

形式

  • 通过使网络过载来干扰甚至阻断正常的网络通讯;
  • 通过向服务器提交大量请求,使服务器超负荷;
  • 阻断某一用户访问服务器;
  • 阻断某服务与特定系统或个人的通讯。

巨人的肩膀

最后😘

由于自己最近也在复习嘛,所以整个系列与其说是博客,不如说是笔记,会持续进行补充和更新,也欢迎纠错,看到会及时修改哒!
温故而知新,希望我们都可以保持本心,念念不忘,必有回响。

最后的最后

给自己的小组卖个安利,欢迎热爱前端的小伙伴加入我们,一起学习,共同进步【有意请留言或私信,社畜搬砖不及时,但看到会立刻回复】 💗💗💗💗💗