跨域
2020-04-16 11:08:19 1 举报
AI智能生成
登录查看完整内容
跨域解决办法梳理
作者其他创作
大纲/内容
跨域
解决办法
CORS 机制
server.js
const express = require(\"express\");const app = express();const port = 3003;app.get(\"/\
附带身份凭证的请求
Fetch 与 CORS 的一个有趣的特性是,可以基于 HTTP cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要 设置 XMLHttpRequest 对象 或者 Request 构造器的 某个特殊标志位。
对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。
后台代理
Nginx代理跨域
Nginx配置解决iconfont跨域
浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。location / { add_header Access-Control-Allow-Origin *;}
Nginx反向代理接口跨域
原理
同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。
思路
通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
配置
Nginx
#proxy服务器server { listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用 add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为* add_header Access-Control-Allow-Credentials true; }}
前端
var xhr = new XMLHttpRequest();// 前端开关:浏览器是否读写cookiefont color=\"#c41230\
Nodejs后台
Nodejs中间件代理跨域
node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。
http-proxy-middleware这里说是可以用于线上以后遇到了再说吧,自己不好尝试线上环境
利用node + express + http-proxy-middleware搭建一个proxy服务器。
中间件服务器
var express = require('express');var proxy = require('http-proxy-middleware');var app = express();font color=\"#c41230\
开发环境下的跨域
利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域信息了。
JSONP
只能够实现get请求
index.js
function callback(res) { console.log(\"res:\"); console.log(res);}let script = document.createElement(\"script\");script.src = `${url}?callback=callback`;document.body.appendChild(script);
const express = require(\"express\");const app = express();const port = 3003;font color=\"#c41230\
postMessage
语法
otherWindow
其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message
将要发送到其他 window的数据。它将会被结构化克隆算法序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。
targetOrigin
通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串\"*\"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
示例
a.html(http://www.domain1.cn/a.html)
<iframe id=\"iframe\" src=\"http://www.domain2.cn/b.html\" style=\"display:none;\
HTMLIFrameElement.contentWindow
contentWindow属性返回<iframe>元素的Window对象。你可以使用这个Window对象来访问iframe的文档及其内部DOM。contentWindow为只读,但是可以像操作全局Window对象一样操作其属性。
b.html(http://www.domain2.cn/b.html)
window.parent
WebSocket协议跨域
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
<div>user input:<input type=\"text\"></div><script src=\"https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js\
Nodejs socket后台
document.domain + iframe
要求主域名相同
两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
父窗口:(http://www.domain.com/a.html)
<iframe id=\"iframe\" src=\"http://child.domain.com/b.html\"></iframe><script> document.domain = 'domain.com'; var user = 'admin';</script>
子窗口:(http://child.domain.com/b.html)
<script> document.domain = 'domain.com'; // 获取父窗口中变量b style=\
window.name + iframe
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
a.html:(http://www.domain1.com/a.html)
proxy.html:(http://www.domain1.com/proxy.html)
中间代理页,与a.html同域,内容为空即可。
b.html:(http://www.domain2.com/b.html)
<script> window.name = 'This is domain2 data!';</script>
location.hash + iframe
a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
实现
A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。
<iframe id=\"iframe\" src=\"http://www.domain2.com/b.html\" style=\"display:none;\"></iframe><script> var iframe = document.getElementById('iframe');font color=\"#c41230\
<iframe id=\"iframe\" src=\"http://www.domain1.com/c.html\" style=\"display:none;\"></iframe><script> var iframe = document.getElementById('iframe'); // 监听a.html传来的hash值,再传给c.html// 我的理解,这里其实 b 页面可以做一些处理后再传递给 c// b 页面不做处理的话,就没有必要绕这么一大圈了,那就是 a 页面自己传数据给自己了 window.onhashchange = function () { iframe.src = iframe.src + location.hash; };</script>
c.html:(http://www.domain1.com/c.html)
<script> // 监听b.html传来的hash值font color=\"#c41230\
参考链接
https://segmentfault.com/a/1190000011145364
0 条评论
回复 删除
下一页