HTTP 请求报文和响应报文
请求报文
- 请求行: 请求方法 url 协议版本 换行符
- 请求头部
- 空行
- 请求体
响应报文
- 响应行: 协议版本 状态码 状态码原因短语
- 响应头
- 空行
- 响应体
网络模型
OSI 七层模型
- 应用层:最靠近用户的议程,如:HTTP,FTP 等协议;
- 表示层:提供用于应用层数据的编码和转换功能,如:base64 对数据的编解码;
- 会话层:负责建立,管理和终止表示层实体之间的通信会话;
- 传输层:建立了主机端到端的连接,如:TCP,UDP 协议;
- 网络层:通过 IP 寻址来建立两个节点之间的连接;
- 数据链路层:数据传输路线;
- 物理层:实际最终信号的传输;
TCP/IP 四层模型
- 应用层
- 传输层
- 网络层
- 链接层
还有一个五层模型,但是都大同小异,只是将七层模型中的几层做了合并。
HTTP1.1 和 HTTP2.0 的区别
- 二进制协议:
HTTP2.0
上一个二进制协议,在HTTP1.1
版本,报文的头信息必须是文本,数据体可以是文本也可以是额二进制。HTTP2.0
则是一个彻底的二进制协议,头信息和数据体都是二进制,统称为“帧”,可以分为头信息帧和数据帧。帧的概念是它实现多路复用的基础。 - 多路复用:
HTTP2.0
实现了多路复用,它依然使用TCP
连接,但是在一个连接里,客户端和服务端都可以同时发送多个请求或响应。而且不用按照顺序一一发送,这样就避免了队头堵塞的问题。 - 数据流:
HTTP2.0
使用了数据流概念,因为HTTP2.0
的数据包不按顺序发送,同一个连接里连续的数据包可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP2.0
将每个请求或响应的所有数据包,称为一个数据流,每个数据流都有一个唯一编号。 - 头信息压缩:
HTTP2.0
实现了头信息压缩,由于HTTP1.1
协议不带状态,每次请求都必须附上所有信息,所以请求的很多字段都是重复的,这会造成浪费。HTTP2.0
的头信息会压缩后再发送并且客户端和服务端同时维护一张头信息表,所有字段都会存入表中,生成一个索引,以后就不用发送这些字段,只发送索引即可。 - 服务器推送:
HTTP2.0
允许服务器未经请求主动向客户端发送资源,这样可以减少一些延迟时间。
关于 HTTP3.0
HTTP3.0 基于 UDP
实现了类似于 TCP
的多路复用数据流,传输可靠性等功能,这套功能被称为 QUIC
协议。
- 流量控制,传输可靠性功能:
QUIC
在UDO
的基础上增加了一层来保证数据传输可靠性; - 集成
TLS
加密功能; - 多路复用;
- 快速握手;
目前仅做简单了解。
HTTP 和 HTTPS 的区别
HTTPS
协议需要CA
证书,HTTP
不需要;HTTP
协议是无状态的,HTTPS
是由SSL
和HTTP
协议构建的可进行加密传输的网络协议;
可以理解为 HTTPS 是在 HTTP 和 TCP 之间加了一层安全协议(TLS/SSL)。
HTTPS 是如何保证安全的
先理解两个概念:
- 对称加密:即通信双方使用同一个密钥进行加解密;
- 非对称加密:包含私钥和公钥,使用私钥加密的数据只有对应的公钥才能解密,同理,公钥的数据只有对应的私钥才能解密,通信双方都有一套自己的密钥对,在通信之前双方会把自己的公钥先发给对方,然后对方拿着公钥来加密数据并发送,双方通过自己手里的私钥来完成解密;
这样看非对称加密更加安全,但是非对称加密带来的问题就是速度慢,影响性能。
HTTPS 使用的方案:
结合两种加密方式,将对称加密的密钥使用非对称加密的公钥进行加密,然后双方可以通过非对称加密后的密钥来使用对称加密来通信。
但是这样存在一个漏洞,即假如通信双方之间存在一个中间人暗中把两人通信的公钥换成了自己的公钥,这样中间人就能轻松破解双方发送的数据了。
所以这个时候就需要一个安全的第三方颁发证书(CA)用来证明身份。
什么是队头阻塞
队头阻塞是由 HTTP 基本的“请求 - 应答”模型造成的,HTTP
规定报文必须是”一发一收“,这就形成了一个先进先出的”串行“队列,队列里的请求没有优先级,只有先后顺序,此时如果队头的请求处理太慢,后面的请求就只能被迫等待,这就是队头阻塞。
当输入 URL 到页面渲染发生了什么
- 浏览器解析
URL
并检查缓存决定是否发出请求; DNS
解析:首先会判断本地是否有该域名的IP
地址缓存,没有就向本地DNS
服务器发起请求,如果没有就会接力一直查到根域名服务器;- 获取目的主机 MAC 地址:因为数据链路层的发送需要加入双方的 MAC 地址;
TCP
三次握手(如果是HTTPS
还需要一个TLS
的四次握手过程);- 页面发送请求,服务器处理并响应;
- 页面渲染:首先根据
html
构建dom
树,然后解析css
构建cssOM
树,两者构建render
树,根据render
树完成布局,浏览器通过渲染线程进行绘制; TCP
四次挥手;
浏览器的缓存
浏览器向服务端发送请求,服务器响应请求结果和缓存规则,浏览器将请求结果和缓存标识存入浏览器缓存中。
缓存位置
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
Service Worker
Service Worker
是运行在浏览器背后的独立线程,可以用来实现缓存功能,使用 Service Worker
必须是 HTTPS
协议。因为 Service Worker
中涉及到请求拦截,必须通过 HTTPS
协议来确保安全。
使用步骤:
- 注册
Service Worker
- 监听到
install
事件缓存需要的文件 - 在下次用户访问时,通过拦截请求的方式查询是否存在缓存。
Memory Cache
Memory Cache
就是内存缓存,读写比磁盘高效,但是缓存持续性很短,会随着进程的释放而释放(如:我们关闭 Tab
页内存中的缓存就释放了),而且内存缓存空间较小。
Disk Cache
磁盘缓存,读写相对较慢,但是胜在空间和存储时长。
Push Cache
推送缓存是 HTTP2.0
的内容,当以上三种缓存都未命中,才可能使用。它只存在会话过程中,一旦会话结束就会释放。
DNS 简介
DNS 协议是什么
DNS
是域名系统(Domain Name System)的缩写,提供域名到 IP
的转换服务。它是由一个分层的 DNS
服务器组成的分布式数据库。
DNS
同时使用 TCP
和 UDP
协议。
- 在区域传输使用
TCP
协议;(副域名服务器会定时向主域名服务器发起数据同步,这就是区域传输)- 原因: 内容多,确保可靠准确。
- 在域名解析的时候使用
UDP
协议;- 原因: 内容少,响应快。
DNS 解析
DNS 解析是一个包含迭代查询和递归查询的过程。
- 递归查询:查询请求发出后,本地域名服务器代为向下一级域名服务器发出请求,最后向用户返回查询结果。(通过递归查询用户只需要发送一次查询请求)
- 迭代查询:查询请求发出后,本地域名服务器只能拿到单次查询结果,如果结果没有,本地域名服务器需要再向下一级发出请求。(迭代查询需要用户发出多次查询请求)
一般用户向本地 DNS 服务器发出请求是递归查询,本地 DNS 服务器向其他域名服务器发起请求是迭代查询。这样能保证用户只发送一次查询请求并且本地 DNS 服务器拿到结果并给到用户。
TCP 和 UDP
TCP
TCP
是面向连接的,可靠的流协议。
- 面向连接:通信前双方必须通过三次握手建立可靠连接;
- 仅支持单播传输:每条
TCP
连接只有两个端点,只能进行点对点传输,无法做多播和广播; - 面向字节流:不保留报文边界的情况下以字节流的方式传输;
- 可靠传输:为了保证报文传输可靠,它会给每个包一个序号,序号可以保证按顺序,并可以让接收方根据序号发送确认码,发送方在一定时间内没收到确认码就会进行重传;
- 提供拥塞控制:当网络拥塞时,
TCP
能减小向网络注入数据的速率和数量,缓解拥塞; - 提供全双工通信:允许通信双方在任何时候都可以发送数据;
TCP 拥塞控制机制
- 慢启动:开始的时候不会发送大量数据,会慢慢增大拥塞控制窗口;
- 拥塞避免:根据接收方发送**是否确认(告诉发送方有丢包)**来判断网络是否拥塞,如果没有收到,会缩小拥塞控制窗口从新慢启动;
- 快速重传:发送方只要连续收到三个接收方发送的重复确认就立即重传对方尚未收到的报文段;
- 快速恢复:当一段时间没有出现是否确认,
TCP
会认为网络没有出现拥塞,此时不执行慢启动算法,而是快速扩大拥塞控制窗口,加大数据传输;
三次握手
TCP
三次握手的过程就是相互确认初始序号的过程,告诉对方,什么样的序号报文段能够正确接收。
第三次握手的作用是客户端对服务端的初始序号的确认,如果是两次握手,服务端就无法确认自己的序号是否得到客户端的认可。
四次挥手
- 当服务端收到客户端结束连接的请求;
- 此时服务端可能还有数据需要传输,它只能告诉客户端,我知道你要关闭连接了;
- 当数据发送完,服务端会告诉客户端可以关闭连接了;
- 客户端确认关闭连接,此时客户端还要等待一段时间来确认发送给服务端的确认报文被正确接收;
UDP
UDP
全称是用户数据报协议,是一种处理数据包的无连接的协议。
- 面向无连接:不需要像
TCP
通过三次握手建立连接,直接发送数据,并且不会对数据做任何处理; - 有单播,多播,广播;
- 不可靠性:无连接肯定不可靠,而且不会关心接收方是否收到数据;
- 没有拥塞控制:以恒定速度发送数据,这样容易丢包;
- 头部开销小,高效;
两者应用场景
TCP
: 接口请求,文件传输,远程登录;UDP
:直播,在线视频,聊天,网络语音电话
CORS
CORS
是一个 W3C
标准,它允许浏览器向跨源服务器,发出 XMLHttpRequest
请求,从而克服 AJAX
只能同源使用的限制。
浏览器将 CORS
请求分为两种:
-
简单请求:
-
请求方法为:
HEAD, GET 或 POST
-
HTTP
头信息:|- 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
字段,便抛出异常。
除了上面的头信息,一般会有以下三个相关头信息:
-
Access-Control-Allow-Origin
该字段是必须的。表示许可范围的域名,通常有两种值:请求时 Origin 字段的值或者 *(星号)表示任意域名。
-
Access-Control-Allow-Credentials
该字段可选。布尔值,表示是否允许在
CORS
请求之中发送Cookie
。若不携带Cookie
则不需要设置该字段。当设置为true
则Cookie
包含在请求中,一起发送给服务器。还需要在AJAX
请求中开启withCredentials
属性,否则浏览器也不会发送Cookie
。let xhr = new XMLHttpRequest(); xhr.withCredentials = true;
复制代码注意: 如果前端设置 Access-Control-Allow-Credentials
为 true
来携带 Cookie
发起请求,则服务端 Access-Control-Allow-Origin
不能设置为 *
。
-
Access-Control-Expose-Headers
该字段可选。可以设置需要获取的字段。因为默认
CORS
请求时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到以下 6 个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma
。
非简单请求的 CORS
流程
请求方法是PUT/DELETE或者 Content-Type: application/json
类型的请求。
在非简单请求发出 CORS
请求时,会在正式通信之前增加一次 “预检”请求(OPTIONS
方法),来询问服务器,本次请求的域名是否在许可名单中,以及使用哪些头信息。
当 “预检”请求 通过以后,才会正式发起 AJAX
请求,否则报错。
预检请求
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
User-Agent: Mozilla/5.0...
...
预检响应
当预检请求通过以后,在预检响应头中,会返回 Access-Control-Allow-
开头的信息,其中 Access-Control-Allow-Origin
表示许可范围,值也可以是 *
。
当预检请求拒绝以后,在预检响应头中,不会返回 Access-Control-Allow-
开头的信息,并在控制台输出错误信息。
网络安全
CSRF
概念
跨站点请求伪造请求
常见场景: 以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账等等。
简单理解流程:
登录信任网站生成登录 cookie
, 携带 cookie
访问危险网站, 危险网站带着 cookie
去访问信任网站并伪造用户进行操作
服务端防御 CSRF 攻击
- 在表单里增加
Hash
值, 随用户的请求一起发给服务端进行认证; - 验证码;
- 请求头部添加
token
:三方跨站请求并不能获取到头部的
token,本站的接口在请求前都会在请求头增加
token用于身份鉴权,三方请求并不会携带
token;`
XSS
概念
XSS
攻击,一般是指攻击者通过在网页中注入恶意脚本,当用户浏览网页时,恶意脚本执行,控制用户浏览器行为的一种攻击方式。
常见 XSS
危害有:
-
窃取用户
Cookie
,获取用户隐私,盗取用户账号。 -
劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等。
-
强制弹出广告页面,刷流量,传播跨站脚本蠕虫,网页挂马等。
-
结合其他漏洞,如
CSRF
漏洞,实施进一步的攻击。
防御方法
-
浏览器自带防御
(x-xss-Protection)
-
白名单
-
内容安全策略(
CSP)
通过
HTTP
头信息的Content-Security-Policy
的字段:Content-Security-Policy: script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:
通过网页的
<meta>
标签:<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
上面代码中,
CSP
做了如下配置:脚本: 只信任当前域名
-
<object>
标签: 不信任任何 URL,即不加载任何资源 -
样式表: 只信任
cdn.example.org
和third-party.org
-
页面子内容,如
<frame>、<iframe>
: 必须使用HTTPS
协议加载 -
其他资源: 没有限制
启用后,不符合
CSP
的外部资源就会被阻止加载。 -
-
客户端对用户输入的内容进行安全符转义,服务端对上交内容进行安全转义;
-
HTTP-only Cookie
: 禁止JavaScript
读取某些敏感Cookie
,攻击者完成XSS
注入后也无法窃取此Cookie
。
前端网络优化
利用缓存
- 协商缓存和强缓存;
- CDN缓存;
Service Work
;
缩减请求
- 图片压缩;
- 合并请求;
- 精灵图;
预加载
- 被标记为
prefetch
的资源,将会被浏览器在空闲时间加载。 preload
通常用于本页面要用到的关键资源,包括关键js
、字体、css
文件。preload
将会把资源得下载顺序权重提高,使得关键数据提前下载好,优化页面打开速度。
<link rel="prefetch"></link>
<link rel="preload"></link>
资源加载位置
- css会影响渲染,尽量放在文件头部;
- js会阻塞渲染,注意放在文件尾部,或者配合使用
defer
,async
;
常见的状态码含义
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
,表明服务器暂时处于超负载或正在停机维护,无法处理请求