Leo:跨域啦,跨域啦,求后端小哥开放白名单吧
大佬:自己解决
Leo:/(ㄒoㄒ)/~~
记得以前最频繁的处理跨域需求就是本地调不通测试站点的接口,只好找后端重新部署一次,开放CORS限制
后来有了nginx和cli-proxy就方便多了
什么是跨域啦
- 浏览器侧的同源策略,用来限制请求资源交互,减少服务器被攻击的渠道之一
- 服务端侧是没有的,所以有些新入门/不了解的服务端同学会疑惑postman上可以正常请求
什么是同源啦
protocol(协议)、domain(域名)、port(端口)三者一致
http即默认80
https即默认443
说到domain域名,示例map.baidu.com
中
-
- baidu.com叫做二级域名
- map.baidu.com叫做三级域名
而我更倾向于称呼
- baidu.com叫做一级域名,【主域名】
- .com是顶级域,baidu是一级名
- map.baidu.com叫做二级域名,【子域名】
- map是二级名
- 不接受反驳,你上阿里云/腾讯云买的是后缀域和名,可以自行配置多个子域名
- baidu.com叫做一级域名,【主域名】
解决它
1、CORS控制响应头
Access-Control-Allow-Origin
控制哪些域名可以获取资源
通常解决是设置响应头Access-Control-Allow-Origin: *
简单/复杂请求
触发简单:
- Method
- GET、HEAD、POST
- Content-Type
- text/plain、multipart/form-data、application/x-www-form-urlencoded
- header
- Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width
- XMLHttpRequestUpload没有事件监听
- ReadableStream不存在
触发预检:Options
就是除了简单条件以外的,比如put和application/json
ie9请使用jsonp
Origin请求头
- 存在跨域,浏览器带上Origin
- 不存在跨域,请求不带Origin
1 | async xxx(ctx,next){ |
Vary缓存处理
当存在多个域名需要通过CORS时,会存在响应缓存,需要【避免CDN缓存】,可以配置Vary:Origin
1 | const getOrigin = ctx.get('Origin'); |
cookie处理
- withCredentials为true
- Access-Control-Allow-Origin为非 *
- Access-Control-Allow-Credentials 为 true
2、正向代理Node proxy
代理的是客户端
1 | // 本地开发时的接口请求域名设为空 |
charles抓包工具拦截处理代理
在 tools/map remote 中设置Map from和Map to
3、反向代理Nginx
代理的是服务端
1 | location /api { |
4、JSONP
script标签,GET方法
- 定义函数jsonpCallback=function(){}
- 定义请求参数cb=jsonpCallback
- 动态接口返回结果运行jsonpCallback({xxx:xxx})
5、Websocket
客户端和服务器之间存在非HTTP,持久,全双工连接
因为不用HTTP,所以就没限制了
6、window.postMessage
可以在 http 返回头 添加X-Frame-Options: SAMEORIGIN 防止被别人添加至 iframe
<iframe id="frame" frameborder="0" onload="load()" src="http://b.test.com/b.html"></iframe>
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的 iframe 消息传递
7、document.domain + iframe
相同主域名,页面A可以拿到iframe页面B的内容
8、window.location.hash + iframe
A:<iframe src="http://localhost:8080/hash/c.html#name1"></iframe>
C:const iframe = document.createElement("iframe"); iframe.src = "http://localhost:8000/hash/b.html#name2";
document.body.appendChild(iframe);
B:window.parent.parent.location.hash = location.hash;
页面A的url的hash值 -> C AC跨域
页面C的url接收hash值 -> B BC跨域
页面B结果给页面A的hash值 -> A AB跨域
9、window.name + iframe
location 变化,重新加载,name 可以不变
就是先读取一次后换个iframe的src路径重新加载
1 | // A: |
10、浏览器配置
【慎用】
Windows
找到你安装的目录
.\Google\Chrome\Application\chrome.exe –disable-web-security –user-data-dir=xxxx
Mac/Downloads/chrome-data/Downloads/chrome-data
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary –disable-web-security –user-data-dir=