解决使用Charles将页面请求代理到本地devServer后热更新失效的问题

背景

无论是开发/测试/生产环境,我司前端项目都需要在相应环境下的账号中心进行登录,登录后账号中心会将jwt保存至localStorage供其他各项目取用。 前端在进行本地开发时可以选择通过注释代码或手动添加有效jwt至localStorage来绕过登录流程,但更推荐的流程是使用代理将线上域名的请求代理至本地devServer,从而保证流程的一致性。 但使用代理始终存在一个问题,就是热更新会失效,每次更新代码后需要手动刷新浏览器查看效果。

现象

使用charles配置map remote,将线上域名下的页面请求代理至本地

image.png

此时通过线上域名访问正常,打开控制台发现有报错

image.png

首次尝试

那既然有请求失败,那让它成功会不会就能热更新了?

本地devServer默认通过http协议进行交互,那么上面的报错应该是根本就找不到相应服务。那么还是借助charles解决,添加以下map remote规则:

image.png

再次刷新页面,发现错误变了

image.png

直接通过浏览器访问这个链接能看到系统认为证书(charles根证书)是有效的,但chrome却认为证书有问题

image.png

为什么chrome认为证书的common name(172.20.212.82)无效呢?

根据此回答stackoverflow.com/a/37063612

CA Browser Forum规定证书可以签发给IP地址,但必须是公共IP,而不是预留IP! *哪些是预留IP

至此我们可以确定,Chrome会因为172.16.0.0–172.31.255.255是一个内网预留的ip段而直接报ERR_CERT_COMMON_NAME_INVALID

第二次尝试

既然不能用本地ip发起这个请求,那么可以通过devServe.public修改访问本地服务的地址

image.png

并且为path为/sockjs-node的请求添加map remote规则

image.png

添加完成后刷新页面,此时页面在不断发起3个请求

image.png

第1个请求已经可以顺利代理到本地并拿到响应,但第2个请求竟是个websocket请求,还需添加相应map remote规则

image.png

第3个请求则直接返回了一个错误响应,想必这就是页面不断在轮询的原因

image.png

可以通过添加devServer.disableHostCheck = true 绕过对请求发起域名的检查

image.png

热更新原理

看到这里你可能对热更新的工作原理产生了一点似是而非的感觉。 让我们从头梳理一下。

  1. 起初devServer返回的前端页面会在后台向/sockjs-node/info?t=xxx发起请求,尝试获取能否建立websocket链接等信息

image.png 2. 如果请求拿到成功响应,接下来会向/sockjs-node/xxx/xxx/websocket尝试建立websocket链接,实现全双工通信

image.png

  1. 如果websocket连接失败,则将前后端通信方式降级为长链接

image.png

  1. 当代码发生改变,开发者保存代码,devServer重新触发编译流程,webpack生成新的模块,并在生成成功后通过websocket或长链接通知前端

image.png 5. 前端通过hash请求一个json和一个js文件

image.png

json文件当中,h会做为下一个hash,用于请求新的json和js文件

c.app = true表示app模块会被更新

image.png

js文件当中已经包含了对webpackHotUpdate方法的调用(非常典型的jsonp),会在拿到响应后执行热更新逻辑

image.png 6. 至此更新流程告一段落

总结

我们了解了在代理以后实现devServer热更新需要至少保证:

  1. /sockjs-node/info?t=xxx发起的请求能拿到成功响应
  2. /sockjs-node/xxx/xxx/websocket发起的请求能拿到101响应(websocket协议升级成功)/sockjs-node/xxx/xxx/xhr_streaming?t=xxx的请求能拿到成功响应(长链接)

以及

  1. chrome会认为给预留ip段签发的证书无效
  2. 热更新前后端交互基本流程

猜你喜欢

转载自juejin.im/post/7111974384599826440