从历史悠久的一个问题开始本文~
地址栏输入url发生什么
- 浏览器接收到URL,网络请求线程开启
- 一个完整的H撒 TTP请求发出
- DNS解析:浏览器自身DNS缓存 -> 搜索系统自身DNS缓存 -> 系统hosts文件查找 -> 本地域名服务器查询 -> 迭代的方式查询根域名服务器
- TCP连接:三次握手、四次挥手
- 发送HTTP请求
- 服务器接收到请求并转到具体的处理后台
- 前后台之间的HTTP交互和涉及的缓存机制
- 浏览器接收到数据包后的关键渲染路径
- 解析HTML和CSS文件,构建DOM和CSSOM
- 将两个对象模型合并为渲染树
- 从DOM树的根节点向下遍历子节点,忽略不可见的节点(脚本标记不可见、CSS隐藏不可见)
- 在CSSOM中为每个可见的子节点找到对应的规则并应用
- 根据得到的渲染树计算在视图中的具体位置和大小,输出的是“盒模型”
- 绘制阶段,将每个节点的具体绘制方式转化为屏幕上的实际像素
- JS引擎的解析
网络模型
OSI七层模型
- 物理层
- 数据链路层
- 网络层
- 传输层
- 会话层
- 表示层
- 应用层
TCP/IP四层模型
- 应用层:应用层、表示层、会话层:HTTP
- 传输层:传输层:TCP/UDP
- 网络层:网络层:IP
- 数据链路层:数据链路层、物理层
TCP/UDP
- tcp是基于连接的,可靠性高;udp是基于无连接的,可靠性较低
- 由于tcp是连接的通信,需要有三次握手、重新确认等连接过程,会有延时,实时性差;由于协议所致,安全性较高;而udp无连接,无建立连接的过程,因而实时性较强,安全略差
- 在传输相同大小的数据时,tcp首部开销20字节;udp首部开销只有8个字节,tcp报头比udp复杂,故实际包含的用户数据较少。tcp无丢包,而udp有丢包,故tcp开销大,udp开销较小
- 每条tcp连接只能是点到点的;udp支持一对一、一对多、多对一、多对多的交互通信
三次握手、四次挥手
TCP协议基本操作
- 发起连接:SYN(Synchroniation),请求同步
- 断开请求:FIN(Finish),请求完成
- 发送数据:PSH(Push),数据推送
- 接收方收到数据后,都需要给发送方一个ACK(Acknowledgement)响应。请求/响应模型是可靠性的要求,如果一个请求没有响应,发送方会认为自己需要重发这个请求
三次握手过程
- 第一次握手:客户端向服务器端发送序列号 seq=x 的标识,表示开始建立连接
- 第二次握手:服务器端回发一个 ack=x+1 的标识,表示确认收到第一次握手,同时发送自己的标识 seq=y:客户端确认自己发出的数据能够被服务器端收到
- 第三次握手:客户端发送 ack=y+1 的标识,标识确认收到第二次握手。服务器端确认自己发出的数据能够被客户端收到。
四次挥手过程
- 客户端主动关闭,向服务器发FIN报文
- 服务端接收后通知应用进程并向客户端发送ACK确认
- 服务端处理完后被动关闭再次向客户端发送FIN以及ACK,进入LAST-ACK状态,
- 客户端收到服务端发来的FIN后,发送 ACK 给服务端。在等待2MSL后进入CLOSED状态
TCP为什么握手三次、挥手四次
- TCP是一个双工协议,为了让双方都保证在建立连接的时候,连接双方都需要向对方发送SYC(同步请求)和ACK(响应)。
- 握手阶段双方没有繁琐的工作,因此一方发出SYN后,另一方可以将自己的ACK和SYN打包为一条消息回复
- 挥手阶段,双方都有可能有未完成的工作,收到挥手请求的一方,必须马上响应ACK,表示接收到挥手请求;最后等所有工作结束后,再发送请求中断连接FIN,因此4次挥手(不能合并中间两条消息)
- 核心:握手阶段没有其他事情等待,所以可以将响应ACK和SYN打包一次发送;挥手阶段首先是必须马上响应ACK,其次是需要等所有请求都结束后,再中断连接
HTTP1,1.1,2,3的区别
- HTTP/1.0 增加 HTTP 头,丰富传输资源类型,奠定互联网发展基础。
- HTTP/1.1 增加持久连接、管线化、响应分块,提升了 HTTP 传输效率。
- HTTP/2 采用二进制传输格式,通过 HTTP 多路复用、头部压缩、服务器端推送,将传输效率在 HTTP + TCP 架构上发挥到了极致。
- HTTP/3 将传输层替换为 QUIC,通过改进的拥塞控制、流量控制、0-RTT 建连、传输层多路复用、连接迁移等特性,进一步提升了 HTTP 传输效率
HTTP1.0
- 特点:
- 请求端增加 HTTP 协议版本,响应端增加状态码。
- 请求方法增加 POST、HEAD。
- 请求端和响应端增加头部字段。
- Content-Type 让响应数据不只限于超文本。
- Expires、Last-Modified 缓存头。
- Authorization 身份认证。
- Connection: keep-alive 支持长连接,但非标准。
- 痛点:
- TCP 连接无法复用。
- HTTP 队头阻塞,一个 HTTP 请求响应结束之后,才能发起下一个 HTTP 请求。
- 一台服务器只能提供一个 HTTP 服务。
HTTP1.1
可以并行发起多个请求,并且也能复用同一个 TCP 连接,传输效率得到了提升。但响应端只能按照发送的顺序进行返回,为此很多浏览器会为每个域名至多打开 6 个连接,用增加队列的方式减少 HTTP 队头阻塞
- 特点:
- 持久连接:HTTP/1.1 默认开启持久连接,在 TCP 连接建立后不立即关闭,让多个 HTTP 请求得以复用。
- 管线化技术:HTTP/1.1 中,多个 HTTP 请求不用排队发送,可以批量发送,这就解决了 HTTP 队头阻塞问题。但批量发送的 HTTP 请求,必须按照发送的顺序返回响应,相当于问题解决了一半,仍然不是最佳体验。
- 支持响应分块:
- HTTP/1.1 实现了流式渲染,响应端可以不用一次返回所有数据,可以将数据拆分成多个模块,产生一块数据,就发送一块数据,这样客户端就可以同步对数据进行处理,减少响应延迟,降低白屏时间。
- Bigpipe 的实现就是基于这个特性,具体是通过定义 Transfer-Encoding 头来实现的。
- 增加 Host 头:
- HTTP/1.1 实现了虚拟主机技术,将一台服务器分成若干个主机,这样就可以在一台服务器上部署多个网站了。
- 通过配置 Host 的域名和端口号,即可支持多个 HTTP 服务:Host: :
- 增加 Cache-Control、E-Tag 缓存头。
- 增加 PUT、PATCH、HEAD、 OPTIONS、DELETE 请求方法。
- 痛点:HTTP 队头阻塞没有彻底解决,响应端必须按照 HTTP 的发送顺序进行返回,如果排序靠前的响应特别耗时,则会阻塞排序靠后的所有响应。
HTTP2
在 HTTP/2 中发送请求时,既不需要排队发送,也不需要排队返回,彻底解决了 HTTP 队头阻塞问题。对于头部信息,资源缓存等痛点也进行了优化。
- 特点:
- 请求优先级:多个 HTTP 请求同时发送时,会产生多个数据流,数据流中有一个优先级的标识,服务器端可以根据这个标识来决定响应的优先顺序。
- 多路复用:TCP 传输时,不用按照 HTTP 的发送顺序进行响应,可以交错发送,接收端根据帧首部的标识符,就能找到对应的流,进而重新组合得到最终数据。
- 服务器端推送:
- HTTP/2 允许服务器未经请求,主动向客户端发送资源,并缓存到客户端中,以避免二次请求。
- HTTP/1.1 中请求一个页面时,浏览器会先发送一个 HTTP 请求,然后得到响应的 HTML 内容并开始解析,如果发现有
- 头部压缩:
- HTTP/1.1 的头部字段包含大量信息,而且每次请求都得带上,占用了大量的字节。
- HTTP/2.0 中通信双方各自缓存一份头部字段表,如:把 Content-Type:text/html 存入索引表中,后续如果要用到这个头,只需要发送对应的索引号就可以了。
HTTP3
- 主要特点是对传输层进行了优化,使用 QUIC 替换 TCP,彻底规避了 TCP 传输的效率问题。
- QUIC(Quick UDP Internet Connection)是基于 UDP 进行多路复用的传输协议。QUIC 没有连接的概念,不需要三次握手,在应用程序层面,实现了 TCP 的可靠性,TLS 的安全性和 HTTP2 的并发性。在设备支持层面,只需要客户端和服务端的应用程序支持 QUIC 协议即可,无操作系统和中间设备的限制
- 特点:
- 传输层连接更快:HTTP/3 基于 QUIC 协议,可以实现 0-RTT 建立连接,而 TCP 需要 3-RTT 才能建立连接
- 传输层多路复用
- 改进的拥塞控制
- 优化的流量控制
- 加密认证的报文
- QUIC 中报文都是经过加密和认证的,在传输过程中保证了数据的安全。
- TCP 头部没有经过任何加密和认证,在传输过程中很容易被中间网络设备篡改,注入和窃听。
HTTP缓存
强缓存
- expires(1.0):控制缓存失效日期时间戳
- 再次发起请求,比对expires和当前本地时间戳,小于的话说明未过期,直接读缓存
- 对本地时间戳的过分依赖,如果客户端本地与服务器端时间不同步,或主动修改,对于缓存过期的判断无法达到预期
- cache-control(1.1)
- max-age:x :控制响应资源的有效期,以秒为单位的时间长度,表示资源在被请求到后的x秒内有效
- no-cache:强制进行协商缓存; no-store:禁止使用任何缓存策略【互斥】
- private:只能被浏览器缓存; public:浏览器缓存+代理服务器缓存【互斥】
- s-maxage:缓存在代理服务器的过期时长,仅当设置public后生效
- cache-control完美替代,expires仅为向下兼容
协商缓存
- last-modified(1.0)
- 流程:首次请求的响应头里包含此字段,属性值为该文件最近一次修改的时间戳;刷新后,请求头会携带if-modified-since,其值为上次响应头last-modified字段值;服务器收到该请求后,会比较当前资源的修改时间戳与if-modified-since的值,如果相同说明缓存未过期,否则重新请求新文件资源
- 缺点:只是根据文件资源最后修改时间戳来判断,如果资源进行编辑但内容没有更新,也会更新时间戳,造成没必要的请求;因为时间戳单位为秒,如果在毫秒级时间内对文件进行了修改,是无法识别的
- ETag(1.1)
- 服务器为不同资源进行哈希运算所生成的字符串,类似文件指纹,文件内容编码不同,对应ETag值就不同,对资源修改由更精准的变化感知,因此ETag的优先级更高
- 再次发起请求时,请求头字段为IF-None-Match
- 若验证缓存有效,则Content-Length字段值为0
- 生成ETag需要付出额外的计算开销,资源尺寸过大、数量较多、修改频繁,会影响服务器性能
缓存决策
- 是否需要缓存(no-store【涉及用户敏感信息】)
- 是否协商缓存(no-cache)
- 是否可被代理服务器缓存(是public,否private)
- 配置强制缓存过期时间max-age,配置协商缓存的ETag或last-modified
- 不同类型文件做不同缓存策略(HTML no-store)
状态码
- 1xx:表示目前是协议的中间状态,还需要后续请求
- 2xx:表示请求成功
- 3xx:表示重定向状态,需要重新请求
- 4xx:表示请求报文错误
- 5xx:服务器端错误
常用状态码:
- 101 切换请求协议,从 HTTP 切换到 WebSocket
- 200 请求成功,有响应体
- 301 永久重定向:会缓存
- 302 临时重定向:不会缓存
- 304 协商缓存命中
- 400 请求错误
- 401 请求要求身份验证
- 403 服务器禁止访问
- 404 资源未找到
- 405 禁用请求中指定的方法
- 500 服务器端错误
- 502 服务器作为网关或代理,从上游服务器收到无效响应(错误网关)
- 503 服务器繁忙
OPTIONS请求方法及使用场景
- OPTIONS方法是用于请求获得由Request-URI标识的资源在请求/响应的通信过程中可以使用的功能选项。通过这个方法,客户端可以在采取具体资源请求之前,决定对该资源采取何种必要措施,或者了解服务器的性能。该请求方法的响应不能缓存。
- OPTIONS请求方法的主要用途有两个:获取服务器支持的所有HTTP请求方法;用来检查访问权限。
- 例如:在进行 CORS 跨域资源共享时,对于复杂请求,就是使用 OPTIONS 方法发送嗅探请求,以判断是否有对指定资源的访问权限。
WebSocket
- 基于tcp,可靠性传输协议,应用层协议
- WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息;HTTP是单向的
- WebSocket是需要浏览器和服务器握手进行建立连接的,而HTTP是浏览器发起向服务器的连接,服务器预先并不知道这个连接
- WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的
跨域
同源策略
浏览器地址和请求地址的协议、域名、端口号需保持一致,否则,跨域,是浏览器的限制,且是在数据返回的时候判断是否同源,因为如果服务端在请求头开启了CORS,是不会拦截的。
解决方法
- JSONP:利用
<script>的src属性不跨域的方式 - CORS:响应头
Access-Control-Allow-Origin配置相应白名单 - 反向代理:利用其他服务转发,如dev阶段可用Node,prod阶段可用Nginx
正代反代
简言之:正代代理客户端,反代代理服务器
正向代理
类似跳板机,代理访问自己本身不能访问的资源,代理服务器拿到相应资源后,再返给客户端
反向代理
- 服务器根据客户端的请求,从其关系的一组或多组服务器上获取资源,然后再将这些资源返回给客户端,客户端只会得知代理服务器的IP地址,而不知道在代理服务器后面的服务器集群的存在。可能不同请求会被代理到不同服务器上
- 作用
- 保证内网的安全,我们在用反代处理跨域时,可以看到访问的接口域名实际不是真正的接口域名,而且前端服务对应的地址
- 可做负载均衡,通过反向代理服务器来优化网站的负载
网络安全
XSS (cross-site scripting)跨站脚本攻击
- 攻击者添加代码嵌入到页面中,使用户访问时都会执行相应的嵌入代码
- 解决方式:设置cookie时设
http-only,js拿不到
CSRF(Cross Site Request Forgecy)跨站请求伪造
- 过程
- 用户登录站点A,本地记录了cookie
- 没有登出站点A的情况下,登录了危险站点B,B要求访问A
- 站点A没做csrf防御
- 特点:
- CSRF(通常)发生在第三方域名。
- CSRF攻击者不能获取到Cookie等信息,只是使用。
- 防御
- 使用Referer Header确定来源域名: 根据HTTP协议,在HTTP头中有一个字段叫Referer,记录了该HTTP请求的来源地址(https不发送referer)
- 人机验证
- CSRF_TOKEN:可以放在cookie中返回,但一定要设置
http-only,请求时再同时携带token和csrf_token做鉴权;也可以在客户端随机生成一个csrf_token,发请求时再请求的body和cookie里同时加入,服务端验证这俩参数的一致性,否则就是伪造
请求劫持
- DNS劫持:通过修改运营商的本地DNS记录;302跳转方式
- HTTP劫持:向首部主体内容添加内容的攻击称为http响应截断攻击(
%0D%0A%0D%0A表示两个换行,就把http首部和主体分隔开了)
总结
本文从老生常谈的一道面试题开始,到每个细节点的展开阐述,基本涉及到了前端需要了解的绝大部门关于计算机网络的内容,有些未涉及到的大家查漏补缺,职业生涯中碰到网络的问题和面试希望大家都可以迎刃而解~