whisle 代理导致热更新失效

2,101 阅读4分钟

whistle 解决接口跨域问题

特别提醒

修改了 whistle 规则配置后一定要记得点击 save 进行保存!!!保存!!!保存!!!

跨域规则

# 针对所有域名开启跨域规则
* resCors://* # 所有 origin 都返回 access-control-allow-origin: *
* resCors://enable # 根据 origin 的值返回 access-control-allow-origin: 响应的 origin 值
* resCors://use-credentials

whistle 文档解释

# `*` 表示设置 access-control-allow-origin: *
www.example.com resCors://*

#  `enable` 表示设置 access-control-allow-origin: http://originHost
# 及access-control-allow-credentials: true
# 可用于script标签上设置为 `crossorigin=use-credentials`的情形
www.example.com resCors://enable
# 或
www.example.com resCors://use-credentials

resCors · GitBook (wproxy.org)

无法热更新

代理无法代理 localhost

一般情况下用 SwitchyOmega 创建代理规则时,不代理规则中会默认添加本地回环地址,因此导致无法代理本地服务。因此只需要将不需要代理中的域名及IP删掉即可。

2023-01-19-09-58-19-image.png

访问协议错误

GET https://localhost:9988/sockjs-node/info?t=1674093553467 net::ERR_SSL_PROTOCOL_ERROR

配置域名使用的是 https 协议,因此对应的热更新服务也默认使用 https 协议。

要解决此问题需要再可以代理 localhost 的前提下,在 whistle 增加一条规则配置即可

localhost:9988 http://localhost:9988

请求 404

GET https://test.xxx.com/browser-sync/browser-sync-client.js?v=2.27.10 net::ERR_ABORTED 404

因为 whistle 配置中是直接映射到了具体静态资源所在的路径 path ,在相同路径下找不到对应的资源。

解决方法只需要增加对应的 whistle 规则即可。

https://test.xxx.com/browser-sync/ http://localhost:3000/browser-sync/
https://test.xxx.com:3000/browser-sync/socket.io/ http://localhost:3000/browser-sync/socket.io/

请求 502

GET https://test.xxx.com:3000/browser-sync/socket.io/?EIO=4&transport=polling&t=ON7pmSP 502
GET https://test.xxx.com:3000/browser-sync/socket.io/?EIO=4&transport=polling&t=ON7q0B_ 502

因为域名后面出现了端口号 3000。 解决方法也是增加规则,将请求转发至对应的资源处。

https://test.xxx.com:3000/browser-sync/socket.io/ http://localhost:3000/browser-sync/socket.io/

ws连接失败

WebSocket connection to 'wss://test.xxx.com:3000/browser-sync/socket.io/?EIO=4&transport=websocket&sid=MIj3PeG8mSSIgvobAAAY' failed:

跟上面 请求 502 问题相似,也是域名后面多了端口 3000 导致的。

解决办法增加 whistle 规则。

wss://test.xxx.com:3000/browser-sync/socket.io ws://localhost:3000/browser-sync/socket.io/

Invalid Host/Origin header

这是因为 sockjs-node 包中逻辑不认请求响应中的跨域 access-control-allow-origin:test.xxx.com

解决办法是将请求响应中的跨域源设置为通配符(wildcard) *,增加 whistle 规则。

规则中增加重写request

localhost:9988 reqHeaders://{sockjsReq}

规则中增加重写response

localhost:9988 resHeaders://{sockjsRes}

Values中增加 sockjsReq 值,内容为

origin: https://localhost:9988

此规则是为了告诉热更新服务器浏览器使用的还是localhost:9988进行服务器请求的,便于服务器响应对应的跨域源

Values中增加 sockjsRes 值,内容为

access-control-allow-origin: *

此规则是为了告诉浏览器服务器接受浏览器源 https://test.xxx.com,从而绕过同源策略

跨域

使用域名转发至本地服务时导致热更新服务报协议错误。

Access to XMLHttpRequest at 'https://localhost:9988/sockjs-node/info?t=1674092688676' from origin 'test.xxx.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

此错误是因为 sockjs-node-client 中发送 XHR 请求时,将认证属性 withCredentials 设置为了 true, 将源码中 dist 包内的对应赋值改为 false 即可。

XMLHttpRequest.withCredentials 属性是一个 Boolean 类型,它指示了是否该使用类似 Cookies、Authorization Headers (头部授权) 或者 TLS 客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。

在同一个站点下使用 withCredentials 属性是无效的。

此外,这个指示也会被用做响应中 Cookies 被忽视的标示。默认值是 false。 如果在发送来自其他域的 XMLHttpRequest 请求之前,未设置withCredentials 为 true,那么就不能为它自己的域设置 Cookie 值。而通过设置 withCredentials 为 true 获得的第三方 Cookies,将会依旧享受同源策略,因此不能被通过 document.cookie 或者从头部相应请求的脚本等访问。

——来自MDN

Request.credentials - Web API 接口参考 | MDN (mozilla.org)

XMLHttpRequest.withCredentials - Web API 接口参考 | MDN (mozilla.org)

源码如下:

  if ((!opts || !opts.noCredentials) && AbstractXHRObject.supportsCORS) {
    debug('withCredentials');
    // Mozilla docs says https://developer.mozilla.org/en/XMLHttpRequest :
    // "This never affects same-site requests."
    // 此处改为 false ,然后重启项目即可
    this.xhr.withCredentials = false;
  }
  if (opts && opts.headers) {
    for (var key in opts.headers) {
      this.xhr.setRequestHeader(key, opts.headers[key]);
    }
  }

至此,因为配置域名映射服务导致的热更新失效可能出现的问题全部解决,可以愉快地开发了~

水平有限,如有错漏欢迎评论区讨论~