from 从输入 URL 到页面加载的过程?如何由一道题完善自己的前端知识体系!
作为进阶回头再来看看:从输入 URL 到页面加载完成的过程中都发生了什么事情?
后台和前台的 http 交互
http 信息载体
报文一般包含了 通用头部 响应/请求头部 响应/请求体
通用头部
Request URL请求的web服务器地址Request Method请求的方法(getpostdeleteputtraceoptionsheadconnect)Status Code200 表示成功等Remote Address请求的远程地址,转成ip
methods:
HTTP1.0 定义了三种请求方法: GET POST HEAD
以及几种 additional request methods:PUT DELETE LINK UNLINK
HTTP1.1 定义了八种请求方法:get post delete put trace options head connect
下面是常见的状态码
200表示请求成功304自上次请求,请求的资源没有发生过变化,请使用本地缓存400客户端请求有错403禁止访问,比如未登陆的情况下的返回码404资源未找到500服务器内部出错503服务器不可用
常见的状态码范围
1xx指示信息,表示请求已经接受,继续处理2xx成功3xx重定向,表示完成请求需要近一步操作4xx客户端错误,请求有语法错误或者无法实现5xx服务端错误,服务器未能完成合法请求
请求/响应头部
常用的请求头
Accept接收类型,表示浏览器支持的MIME类型,对表服务器返回的Content-TypeAccept-Encoding浏览器支持的压缩类型,比如GZIP,超出类型不支持Content-Type客户端发出去的实体内容的类型Cache-Control指定请求和响应遵守的缓存策略,比如no-cacheIf-Modified-Since对应服务器的Last-Modified,用来匹配看文件是否修改了,精确到1s,是http1.0Expries缓存控制,这个时间之前不会请求,直接使用缓存,http1.0而且用的是服务器时间Max-age代表缓存在本地多少秒,有效时间内不会请求,而是使用缓存,http1.1If-None-Match对应服务器的ETag,用来匹配文件是否修改,非常准,http1.1中Cookie有Cookie并且同域的时候会带上Connection浏览器和服务器通信时对于长链接如何处理,keep-aliveHost请求的服务器URLOrgin最初的请求从哪里来的,精确到端口,Origin比Referer更尊重隐私Referer该页面的来源url,适用于所有类型的请求,会精确到详细页面的地址,csrf拦截常用这个User-Agent用户的客户端信息
常用下响应头
Access-Control-Allow-Headers服务器允许的请求头Access-Control-Allow-Methods服务器允许的请求方法Access-Control-Allow-Origin服务器允许的请求Origin头部,比如*Content-Type服务器返回的实体内容类型Date服务器发送的时间Cache-Control告诉客户端什么情况下可以安全的缓存文档Last-Modified最后的修改时间Expires应该在什么时候认为文档过期了,从而不缓存Max-age客户端本地应该缓存多久,开启了Cache-Control后有效ETag返回实体标签当前值Set-Cookie设置和页面关联的CookieKeep-Alive如果客户端有keep-alive,服务器也会响应Server服务器相关的信息
请求/响应实体
请求实体可以放类似 a=1&b=2 这样的序列化形式,也可以放表单 form data 对象,里面夹杂着文件等
响应实体就是服务端处理以后返回的信息
现在接口请求一般是 json 格式,而页面则是 html 文件,返回给浏览器解析
CRLF
Carriage-Return Line-Feed,代表回车换行,作为分隔符
请求头和实体之间会有一个 CRLF,响应头和响应实体也会有一个 CRLF
1
2
3
CRLF => Windows-style
LF => Unix Style
CR => Mac Style
cookie 优化
cookie 是浏览器的一种本地存储方式,帮助客户端和服务器通信,常用来验证身份,结合服务器的 Session 使用
- 用户登录
- 服务器生成一个
Session,有用户的用户名等 - 会有一个
SessionId,相当于服务器存储中的Key - 服务器在登陆页面中写入
cookie,比如jsessionid=xxx - 浏览器本地有了这个,以后访问同域名下的网站都会带上
cookie,有效时间内无需再次登陆,
加上 httpOnly 那么 js 无法访问了
也可以进行下面的优化,请求静态资源的时候也会加上 cookie 很浪费,可以把他们放在其他域名下
但是多域名拆分的话,因为域名解析很耗时间,会降低请求速度,我们一般使用 dns-prefetch 技术,让浏览器空闲的时候提前解析 dns域名
gzip 压缩
压缩格式,浏览器一般都支持,压缩效率很高,一般在 70%,一般有 apache tomcat 服务器开启
还有一些其他的压缩方法,比如 deflate 但是没有 gzip 流行和高效
所以一般都是服务器开启了 gzip 压缩
长连接和短连接
看下这两个在 tcp/ip 层的定义
- 长连接:一个
tcp/ip上面可以连续发送多个数据包,在tcp连接保持期间,如果没有数据包发送,需要双方发送检测包维持连接,需要自己做在线维持,比如心跳包 - 短连接:双方有数据交换的时候发起一个连接,发送结束以后就断开
在 http 层面
http1.0默认都是短连接,每进行一次http请求,建立一次连接,结束了就断开,比如每一个资源请求就发起一个单独的连接http1.1开始默认用长连接,使用长连接会加上一个Connection: keep-alive,在这种情况下网页打开以后服务器和客户端之间传输http的tcp连接不会断开,如果再次访问这个服务器的页面,会继续使用一条已经建立的连接
不过持续时间也是有限制的,一般在服务器进行配置,当然也需要客户端和服务器都支持
http2.0
下一代规范,说下和 http1.1 的区别
http1.1中每请求一个资源需要开启一个tcp/ip连接,对应的结果就是每个资源对应一个tcp/ip连接,而tcp/ip本身有并发限制,当资源多的时候就慢下来了http2.0中一个tcp/ip连接可以请求多个资源,只要一次tcp/ip请求可以返回多个资源,分割成更小的帧请求,速度更加快
所以如果 http2.0 全面应用,http1.1 里面的一些优化方法就没必要了,比如打包成精灵图,静态资源多域名拆分等
- 多路复用,一个
tcp/ip可以请求多个资源 - 首部压缩,
http头部压缩,减小体积 - 二进制分帧,在应用层和传输层之间加了一个二进制分帧层,改进传输性能,实现低延迟和高吞吐
- 服务器推送,服务器可以对客户端的一个请求发出多个响应,也可以主动通知客户端
- 请求优先级,如果流被赋予了优先级,会基于这个优先级处理,由服务器决定需要多少的资源来处理这个请求
https
在请求前,会建立 ssl,确保接下来的请求都是加密的,无法轻易截取分析
要把网站升级成 https 需要后端支持,申请证书什么的
而由于需要建立额外的安全连接和加密等,开销也会更加大
下面我们关心下 SSL/TLS 握手过程
- 浏览器请求一个
SSL连接,并向服务器发送一个随机数client random和客户端支持的加密方法,比如rsa加密,这个是明文传输的 - 服务器从中选出一组加密算法和
hash算法,回复一个随机数server random,并把自己的身份信息以证书的方法返回给客户端(证书包含了服务器的网站地址,非对称加密的公钥,证件颁发机构等信息) - 浏览器收到了服务器的证书以后
- 验证证书的合法性(颁发的结构是否合法,包含的地址和访问的地址是否一致),如果可信的会有一个绿色的小锁头
- 用户接收到证书以后,会产生一个新的随机数
Premaster secret,证书中的公钥和指定的加密方法加密Premaster secret,发送给服务器 - 利用
client randomserver randomPremaster secret通过一定的算法生成http连接传输的对称加密key-session key - 使用约定好的
hash算法计算握手信息,并且使用生成的session key对信息进行加密,然后把之前算出来的所有信息返回给服务器
- 服务器接收到了浏览器的信息
- 利用已知的加解密算法和自己的私钥进行解密,获得
Premaster secret - 和浏览器一样的规则生成
session key - 使用
session key解密浏览器发来的握手信息,验证hash和浏览器发过来的是不是一致 - 使用
session key加密一段握手信息给浏览器
- 利用已知的加解密算法和自己的私钥进行解密,获得
- 浏览器解密和计算握手信息的
hash,如果和服务器发过来的一样,握手结束
之后所有的 http 请求,使用前面的 session key 进行对称加密算法加密
