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删掉即可。
访问协议错误
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-siteAccess-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]);
}
}
至此,因为配置域名映射服务导致的热更新失效可能出现的问题全部解决,可以愉快地开发了~
水平有限,如有错漏欢迎评论区讨论~