客户端和服务端之间的信息通信
- ajax / fetch 数据交互
- 跨域处理方案:ajax、fetch、jsonp、postMessage
- 资源获取【html|、css、js、image、音视频】
- webscoket
请求:客户端把信息传递给服务器或者向服务器发送请求
响应:服务器接受客户端信息并且返回给客户端相关的内容
HTTP 报文:客户端和服务器之间的传输的所有内容
起始行:基本信息【包含 HTTP 的版本等】
请求起始行:GET【请求方式】 xxx【请求地址】 HTTP/1.1【HTTP 版本号】
响应起始行:HTTP/1.1【HTTP 版本】 200【HTTP 响应状态码】 OK【状态码描述】
首部(头):请求头【客户端->服务器】、响应头【服务器->客户端】
主体:请求主体【客户端->服务器】、响应主体【服务器->客户端】
客户端和服务器之间的数据传输,依托于网络【通信模式 TCP/IP… 传输协议 HTTP/HTTPS/FTP…】
从输入 URL 地址到看到页面,中间的经历
- URL 解析
- 检查缓存【强缓存、协商缓存(针对资源文件请求);本地缓存(针对数据请求)】
- DNS 服务器解析【域名解析:根据域名解析出服务器外网 IP】
- TCP 三次握手【建立客户端和服务器之间的网络连接通道】
- 基于 HTTP/HTTPS 等协议,实现客户端和服务端之间的信息通信
- TCP 四次挥手【把建立好的网络通道释放掉】
- 客户端渲染【呈现出页面和效果】
URL 解析
URI:统一资源标识符
- URL:统一资源定位符
- URN:统一资源名称
传输协议: 用什么样的协议负责客户端和服务端的信息传输
HTTP:超文本传输协议
除了传输文本还可以传输其余的信息,例如:文件流、二进制或者 Buffer 格式或者 BASE64 格式的数据
HTTPS:HTTP + SSL(TSL) 更安全的 HTTP,传输的内容经过加密
FTP:文件的上传下载
域名: 对服务器外网 IP 的一个重命名
www.baidu.com
- 顶级域名
baidu.com
- 一级域名
www.baidu.com
- 二级域名
video.baidu.com
- 三级域名
image.video.baidu.com
域名和服务器购买完后,需要在 DNS 服务器生成一条解析记录,用于以后的 DNS 解析
端口号: 区分同一台服务器上不同的服务的
取值范围:0~65535 之间
默认端口号:浏览器会根据输入的协议,给与默认端口号
HTTP -> 80
HTTPS -> 443
FTP -> 21
请求资源的路径名称: 基于路径找到客户端需要的资源文件
看到的 URL 地址可能是重写后的【看到的地址在文件目录不存在】
ajax 数据请求
/api/list
url 重写
动态网址,页面中的内容是无法被搜索引擎收录的(不利于 SEO 优化)
静态化地址
https://item.jd.com/....
,通过 URL 重写为https://item.jd.com/detail.jsp?id=...
https://item.jd.com/info/100000
路径参数【导航】https://www.baidu.com/info?id=100000
问号传参:
把信息参数传递给服务器,GET 系列请求一般都是这样传递参数
xxx=xxx&xxx=xxx
-> x-www-form-urlencoded 格式如果是页面跳转,把信息传递给另一个页面
HASH 值:
- 锚点定位
- HASH 路由
URL 编译问题:
- encodeURI decodeURI:编译空格和中文,一般编译整个 URL 中的信息(前后端都支持的 API)
- encodeURIComponent decodeURIComponent:编译空格和中文以及一些特殊符号,所以一般只用来编译传递的信息的值,而不是整个 URL(前后端都支持的 API)
- escape unescape(用于客户端页面信息传递或一些信息的编译【cookie 中的中文内容编译】)
- 也可以基于自己设定的加密机制规则处理(对称加密)
- 对于某些数据,需要采用不可解密的(非对称加密),例如:md5
缓存检测
缓存处理是基于 HTTP 网络层进行优化的一个非常重要的手段 【针对资源文件请求】
强缓存还是协商缓存都是服务器设置的,客户端浏览器自己会根据返回的一些信息,进行相关处理,无需前端单独设置东西
缓存位置:
- Memory Cache : 内存缓存(页面没有关闭,只是刷新)
- Disk Cache:硬盘缓存(页面关闭后重新打开)
打开网页:查找硬盘缓存中是否有匹配,如有则使用,如没有则发送网络请求
普通刷新(F5):因 TAB 没关闭,因此内存缓存是可用的,会被优先使用,其次才是硬盘缓存
强制刷新(Ctrl + F5):浏览器不使用缓存,因此发送的请求头均带有 Cache-Control: no-cache
,服务器直接返回 200 和最新内容
强缓存: Expires / Cache-Control
Expires:缓存过期时间,用来指定资源到期的事件(HTTP/1.0)
Cache-Control:
cache-control: public, max-age=2592000
第一次拿到资源后的 2592000 秒内(30 天),再次发生请求,读取缓存中的信息(HTTP/1.1)
- 如果获取的是强缓存信息,HTTP 状态码是 200
- 如果是从服务器成功重新获取,HTTP 状态码也是 200
问题:本地缓存了文件,但是服务对应的资源文件更新了,如何保证获取的是最新的内容?
- 所有请求的资源文件(css / js / 图片)后面都带一个时间戳
- 每一次资源的更新,基于 webpack 生成不同的资源名称(HASH 值)
所以 HTML 永远不会做强缓存,资源文件一般会使用 强缓存+协商缓存
协商缓存: Last-Modified / ETag
Last-Modified:记录服务器资源文件最后一次更新的时间(HTTP/1.0)请求头:
If-Modified-Since
ETag:只要服务器资源文件改变,会生成一个不同的标识(HTTP/1.1)请求头:
If-None-Match
当强缓存失效(不存在)【html 可以做协商缓存】,会校验协商缓存,每一次都会向服务器校验资源是否更新
- 如果没有更新,返回 304 通知客户端读取缓存信息,从本地缓存中获取内容进行渲染
- 如果有更新,返回 200 及最新资源信息,直接渲染,并把最新的 Last-Modified / ETag 和最新的资源信息缓存到本地
数据缓存:
没有缓存数据,从服务器拉取最新数据;有缓存数据,直接读取缓存数据【减少和服务器之间的交互频率,降低服务器压力,也可以提高页面的渲染速度】
- 页面不刷新,某些内容频繁操作,但是数据不是需要实时更新,可以做缓存【不经常更新的数据】
- 页面只要不关闭,直接读取缓存,如果页面关闭,重新打开我们也可以读取缓存中的数据【数据更新频率更低,可以设置过期时间】
客户端存储数据的方案:
- (全局)变量存储【vuex / redux】:页面刷新或关闭后打开,之前存储的数据都没有(内存释放)
- cookie
- webStorage:LocalStorage SessionStorage
- IndexedDB 浏览器数据库存储
- Cache
- Manifest 离线存储
LocalStorage V.S. SessionStorage
- LocalStorage 持久化本地存储(没有过期时间),页面关闭存储内容也是存在的,除非用户手动清除
removeItem clear
- SessionStorage 会话存储,页面关闭后,存储的信息会消息【页面刷新不消失】
Cookie V.S. LocalStorage
Cookie 只允许一个源下最多存储 4KB 内容,所以不能存储太多的数据
本地存储的数据是由同源访问限制的,只允许读取本源下存储的内容
LocalStorage 可以在同源下存储 5MB 内容
Cookie 需要设置过期时间,超过时间就失效,并且有路径限制
LocalStorage 持久化存储,没有过期时间,除非手动清除
Cookie 不稳定
基于安全卫士或浏览器自带的清除操作,会把 Cookie 删除掉,开启无痕浏览,不能存储 Cookie
LocalStorage 不受这些操作影响
Cookie 兼容低版本浏览器
LocalStorage HTML5 新增的 API【不兼容 IE8 以下浏览器】
Cookie 不算严格本地存储
客户端向服务器发送请求,会默认把本地的 Cookie 基于请求头发送给服务器,并且服务器返回的响应头中有 Set-Cookie 字段,浏览器会默认把这些信息种在客户端本地中
LocalStorage 严格本地存储,默认情况下和服务器没有任何关系
想要基于 ajax 获取数据,必须要保证当前页面的运行是在 http/https 协议下,file 文件协议不行
1 | function getData() { |
DNS 解析
- 递归查询
- 迭代查询
多服务器部署
- 弊端:增加了 DNS 解析次数
- 优势:资源合理利用、抗压能力增强、提高 HTTP 并发性【同源并发 HTTP 5~7 个】
每一次 DNS 解析时间预计在 20~120 毫秒
- 减少 DNS 请求次数
- DNS 预获取(DNS Prefetch)
1 | <meta http-equiv="x-dns-prefetch-control" content="on"> |
TCP 三次握手
- seq 序号,用来标识从 TCP 源端向目的端发送的字节流,发起方发送数据时对此进行标记
- ack 确认序号,只有 ACK 标识为 1 时,确认序号字段才有效,ack=seq+1
- 标识位
- ACK:确认序号有效(acknowledge)
- RST:重置连接 (reset)
- SYN:发起一个新连接(synchronous)
- FIN:释放一个新连接(finish)
- seq:序号(sequence)
TCP 三次握手通俗理解,C→S:在不在,S→C:我在你在不在,C→S:我在
三次握手为什么不用两次或四次?
- TCP 作为一种可靠传输控制协议,其核心思想: 既要保证数据可靠传输,又要提高传输的效率
- 两次握手只能保证客户端给服务器端的信息收到了,不能保证服务端给客户端的信息收到了(不够稳定)
- 四次握手就多余了,因为服务端已经知道客户端收到信息了,再给客户端发信息就没有意义了
UDP(User Datagram Protocol) 连接没有三次握手机制
- 相对于 TCP 来讲快
- 不稳定可靠
数据传输
HTTP 报文
- 请求报文
- 响应报文
响应状态码
- 200 OK:请求已成功
- 202 Accepted:服务器已接受请求,但尚未处理(异步)
- 204 No Content:服务器成功处理了请求,但不需要返回任何实体内容
- 301 Moved Permanently:永久重定向
- 302 Move Temporarily:临时重定向
- 304 Not Modified:文档内容没有改变,走协商缓存
- 400 Bad Request : 请求参数有误
- 401 Unauthorized:请求需要权限验证
- 404 Not Found:请求失败,服务器没有这个资源
- 405 Method Not Allowed:请求方法不能由于请求相应资源
- 500 Internal Server Error:服务器未知错误
- 502 Bad Gateway:网关有误
- 503 Service Unavailable:服务器维护或过载,无法处理请求
TCP 四次挥手
服务受到信息和标识后
- 准备客户端需要的东西【需要时间】
- 把信息返回给客户端
但是为了保证消息的及时反馈,此时需要立即告诉客户端:我收到你的东西了,我现在开始准备等我一会
TCP 四次挥手通俗理解,C→S:我要走了,S→C:等下,我看看还有没有数据要传输,C→S:好了,没事了,挂了吧(已经挂了),C→S:挂了
为什么连接的时候是三次握手,关闭的时候却是四次挥手?
- 服务端收到客户端的 SYN 连接请求,可以直接发送 SYN+ACK 报文
- 但关闭连接时,当服务器收到 FIN 报文时,很可能并不会立即关闭连接,所以只能先回复以一个 ACK 报文,告诉客户端:你发的 FIN 报文我收到了,只有等到服务端所有的报文都发送完了,才能发送 FIN 报文,因此不能一起发送,故需要四次握手
为了减少 TCP 握手和挥手的时间,一般都使用 Connection: keep-alive
数据请求:
- 长轮询:设置定时器,每隔多久发送一次请求,拿到最新数据
- 长连接:如果数据没有更新则连接不中断(服务器挂起),监听数据改变
页面渲染
性能优化汇总
利用缓存
- 对于静态资源文件实现强缓存和协商缓存(扩展:文件有更新,如何保证及时刷新?)
- 对于不经常更新的接口数据采用本地存储做数据缓存(扩展:cookie / localStorage / vuex|redux 区别?)
DNS 优化
- 分服务器部署,增加 HTTP 并发性(导致 DNS 解析变慢)
- DNS Prefetch
TCP 的三次握手和四次挥手
- Connection: keep-alive
数据传输
减少数据传输的大小
内容或者数据压缩(webpack 等)
服务器端一定要开启 GZIP 压缩(一般能压缩 60%左右)
大批量数据分批次请求(例如:下拉刷新或者分页,保证首次加载请求数据少)
减少 HTTP 请求的次数
资源文件合并处理
字体图标
雪碧图 CSS-Sprit
图片的 BASE64
CDN 服务器“地域分布式“
采用 HTTP2.0
网络优化是前端性能优化的中的重点内容,因为大部分的消耗都发生在网络层,尤其是第一次页面加载,如何减少等待时间很重要“减少白屏的效果和时间”
- loading 人性化体验
- 骨架屏:客户端骨屏 + 服务器骨架屏
- 图片延迟加载
HTTP1.0 VS HTTP1.1 VS HTTP2.0
HTTP1.0 VS HTTP1.1 区别:
- 缓存处理: HTTP1.0 中主要使用 Last-Modified、Expires 来做缓存判断标准,HTTP1.1 则引入了更多的缓存控制策略:ETag、Cache-Control…
- 带宽优化及网络连接的使用: HTTP1.1 支持断点续传,即返回码是 206(Partial Content)
- 长连接: HTTP1.1 中默认开启
Connection: keep-alive
,一定程度上弥补了 HTTP1.0 每次请求都要创建连接的缺点 - 错误通知的管理: 在 HTTP1.1 中新增了 24 个错误状态响应码,如 409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除…
- Host 头处理: 在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个 IP 地址。HTTP1.1 的请求消息和响应消息都应支持 Host 头域,且请求消息中如果没有 Host 头域会报告一个错误(400 Bad Request)
HTTP2.0 VS HTTP1.x 的新特性:
新的二进制格式(Binary Format): HTTP1.x 的解析是基于文本,基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认 0 和 1 的组合,基于这种考虑 HTTP2.0 的协议解析决定采用二进制格式,实现方便且健壮
header 压缩: HTTP1.x 的 header 带有大量信息,而且每次都要重复发送,HTTP2.0 使用 encoder 来减少需要传输的 header 大小,通讯双方各自 cache 一份 header fields 表,既避免了重复 header 的传输,又减小了需要传输的大小
服务端推送(server push): 例如我的网页有一个 sytle.css 的请求,在客户端收到 sytle.css 数据的同时,服务端会将 sytle.js 的文件推送给客户端,当客户端再次尝试获取 sytle.js 时就可以直接从缓存中获取到,不用再发请求了
1
Link: </styles.css>; rel=preload; as=style, </example.png>; rel=preload; as=image
多路复用(MultiPlexing)
HTTP/1.0 每次请求响应,建立一个 TCP 连接,用完关闭
HTTP/1.1 「长连接」 若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞;
HTTP/2.0 「多路复用」多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其它连接的正常执行;