同源策略与跨域
同源策略:url 的 协议、IP、端口都相同。
跨域:同源策略不满足。
<img>
、<link>
、<script>
:天然允许跨域加载资源
请求跨域解决方案
-
jsonp
- 原理:利用
<script>
,标签没有跨域限制的漏洞,使得网页可以得到从其他来源动态产生的 JSON 数据(前提是服务器支持) - 优点:实现简单,兼容性好
- 缺点:仅支持 GET 方法,容易受到 XSS 攻击
- 原理:利用
-
CORS
-
原理:服务器端设置
Access-Control-Allow-Origin
以开启 CORS。该属性表示哪些域名可以访问资源,如设置通配符则表示所有网站均可访问 -
示例
// app.js var app = express(); // CORS跨域------------------------------------------------------------------------------------- // CORS:设置允许跨域中间件 var allowCrossDomain = function (req, res, next) { // 设置允许跨域访问的 URL(* 表示允许任意 URL 访问) res.header("Access-Control-Allow-Origin", "*"); // 设置允许跨域访问的请求头 res.header("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept,Authorization"); // 设置允许跨域访问的请求类型 res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); // 设置允许服务器接收 cookie res.header('Access-Control-Allow-Credentials', 'true'); next(); }; app.use(allowCrossDomain);
-
-
WebSocket
-
原理:Websocket 是 HTML5 规范提出的一个应用层的全双工协议,适用于浏览器与服务器进行实时通信场景
-
示例
// 在 a 网站直接创建一个 WebSocket 连接,连接到 b 网站即可, // 然后调用 WebScoket 实例 ws 的 send() 函数向服务端发送消息,监听实例 ws 的 onmessage 事件得到响应内容。 var ws = new WebSocket("ws://b.com"); ws.onopen = function(){ // ws.send(...); } ws.onmessage = function(e){ // console.log(e.data); }
-
-
代理转发
-
原理:跨域是为了突破浏览器的同源策略限制,既然同源策略只存在于浏览器,那可以换个思路,在服务端进行跨域,比如设置代理转发。这种在服务端设置的代理称为“反向代理”,对于用户而言是无感知的
另一种在客户端使用的代理称为 “正向代理”,主要用来代理客户端发送请求,用户使用时必须配置代理服务器的网址,比如常用的 VPN 工具就属于正向代理
-
示例
// 1、在 webpack 中代理 // webpack.config.js // 当浏览器发起前缀为`/api`的请求时都会被转发到 `http://localhost:3000` 这个网址, // 然后将响应结果返回给浏览器。对于浏览器而言还是请求当前网站,但实际上已经被服务端转发。 module.exports = { //... devServer: { proxy: { '/api': 'http://localhost:3000' } } }; // 2、在 Nginx 中代理 location /api { proxy_pass http://localhost:3000; }
-
页面跨域解决方案
-
postMessage
-
原理:HTML5 推出了一个新的函数 postMessage() 用来实现父子页面之间通信,而且不论这两个页面是否同源
-
父页面传子页面示例
// parent.html // 父页面地址:https://lagou.com var child = window.open('https://kaiwu.lagou.com'); child.postMessage('hi', 'https://kaiwu.lagou.com'); // child.html // https://kaiwu.lagou.com window.addEventListener('message', function(e) { console.log(e.data); }, false);
-
子页面传父页面示例
// child.html // 子页面地址:https://kaiwu.lagou.com window.opener.postMessage('hello', 'https://lagou.com'); // parent.html // 父页面地址:https://lagou.com window.addEventListener('message', function(e) { console.log(e.data); }, false);
-
-
改域
-
原理:对于主域名相同,子域名不同的情况,可以通过修改 document.domain 的值来进行跨域。如果将其设置为其当前域的父域,则这个较短的父域将用于后续源检查
-
示例
有页面地址是
https://www.lagou.com/parent.html
,在这个页面里面有一个 iframe,其 src 是http://kaiwu.lagou.com/child.html
。这时只要把
http://www.lagou.com/parent.html
和http://kaiwu.lagou.com/child.html
这两个页面的 document.domain 都设成相同的域名,那么父子页面之间就可以进行跨域通信了,同时还可以共享 cookie。但要注意的是,只能把 document.domain 设置成更高级的父域才有效果,
例如在
http://kaiwu.lagou.com/child.html
中可以将 document.domain 设置成 lagou.com。
-