2025年跨域解决方案(跨域解决方案有哪些)

跨域解决方案(跨域解决方案有哪些)nbsp 一 同源策略 nbsp 同源策略 Same origin policy 是由 NetScape 公司在 1995 年提出的一种安全策略 同源策略只是一个约定 提出后被各个浏览器厂商采纳 并以各自的方式实现了同源策略 nbsp nbsp 同源策略 是浏览器最核心也最基本的安全功能 会约束浏览器的行为 nbsp 同源策略会限制浏览器 只允许本域内的脚本读写本域内的资源 不允许访问本域外的资源 判断是否同源 nbsp 判断要素有三 协议 域名 端口号 nbsp



一、同源策略
同源策略(Same origin policy)是由 NetScape 公司在1995年提出的一种安全策略;同源策略只是一个约定,提出后被各个浏览器厂商采纳,并以各自的方式实现了同源策略。

同源策略:是浏览器最核心也最基本的安全功能,会约束浏览器的行为;
同源策略会限制浏览器:只允许本域内的脚本读写本域内的资源,不允许访问本域外的资源。

判断是否同源?
判断要素有三:协议、域名、端口号;
(三者全部一致才视为同源,即属于同一个域;否则视为非同源。)

限制范围
无法共享 cookie, localStorage, indexDB。
无法操作彼此的 dom 元素。
无法发送 ajax 请求。

二、跨域


域(Domain)是Windows网络中独立运行的单位;
域之间相互访问则需要建立信任关系,信任关系是连接在域与域之间的桥梁;
当一个域与其他域建立了信任关系后,2个域之间不但可以按需要相互进行管理,还可以跨网分配文件和打印机等设备资源,使不同的域之间实现网络资源的共享与管理.


跨域:突破同源策略的限制,在两个不同的域之间(非同源页面)实现资源交互。

跨域分类:
1)使用 Ajax 引发的跨域问题
当调用 Ajax 时:调用 Ajax 发送请求的页面 所在的域,和被请求页面所在的域不一致
2)类似页面嵌入 ifream 引起的跨域问题
当操作 ifream 内引入的元素时:ifream 所属页面的域,和 ifream 引入页面的域不一致


三、跨域实现方法?

1. JSONP:
JSONP 就是跨域的一种实现方式。(JSONP 全称 JSON with Padding,是数据格式 JSON 的一种 “使用模式”,可用于解决主流浏览器的跨域数据访问的问题。)
JSONP 是一种非正式传输协议,该协议的一个要点就是允许用户传递一个 callback 参数给服务端,然后服务端返回数据时会将这个 callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

JSONP 的原理:
利用 script 标签不受同源策略影响,可以跨域引入外部资源的特性,让服务器端返回可执行的 JS 函数,将要返回的数据作为参数传进函数,以此实现跨域加载数据的目的
此时,绕过 Ajax,并未使用它,但同样达成了请求数据的目的

[](【备注】——script 标签引用资源得本质是:
1)向 src 发送请求
2)将资源下载到当前页面
3)当资源加载完毕后,把该资源当做 JS 代码来立刻执行——【备注】)

JSONP 的使用:

1、动态创建 script 标签,src 地址指向数据接口,并传递 callback 参数
2、定义数据处理函数
3、服务端接收请求,解析参数,计算数,返回回调函数字符串
4、将回调函数字符串引入页面并作为 JS 去执行:此时会调用数据处理函数,数据会作为数据处理函数的参数被处理计算出一个结果


JSONP 的优缺点
优点
1)因 script 隶属于 HTML 的标签,所以不存在兼容问题

缺点
1)因需使用 URL 引入资源,所以 JSONP 仅支持 get 请求
2)因 script 标签会将资源作为 JS 代码执行,所以可能会被注入恶意代码


2、CORS
CORS 全称 Cross-Origin Resource Sharing,即:跨来源资源共享。它是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,是JSONP模式的现代版


CORS 的原理:
1、当使用 XMLHttpRequest 发送请求时,如果浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin;
2、后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin;
3、浏览器判断该响应头中是否包含 Origin 的值:
4、如果包含浏览器则会处理响应,前端就可以拿到响应数据;
5、如果不包含浏览器直接驳回,此时前端无法拿到响应数据。
(简单来说,就是浏览器匹配请求头和响应头,如果符合要求便可拿到数据,否则无法拿到数据。整个过程都是由浏览器自动完成。这就像一个白名单,代表着谁可以拿到数据。)


CORS 的使用:
前端:正常使用 AJAX 发送请求
服务端:若确定接受请求,则在返回结果中加入响应头:Access-Control-Allow-Origin


CORS 的优缺点:
优点
1)使用简单方便、更为安全
2)支持 POST 请求方式

缺点
1)CORS 是一种新型跨域问题的解决方案:存在兼容问题——仅支持 IE10 以上

3、降域
降域仍是解决跨域问题的一种方案,通过双向设置 document.domain 的值,解决主域名下的跨域问题


降域的原理
比如,有两个二级域名:a.yang.com 和 b.yang.com,可通过设定 document.domain 的值为主域名:yang.com 的方式,突破浏览器的同源策略限制,来获取和操作对方的元素

这就好比,小 A 和小 B,手里拿着城主的令牌,通过哨卡时才能畅行无阻,否则哨卡不让过

这也就决定了,降域具有很大的局限性,适用范围较小,适合在同一主域名下使用;需要有降的空间,方可使用降域方式

降域的使用
A 页面域为:a.yang.com

B 页面域为:b.yang.com

A 和 B 两页面都需加入该行代码:document.domain = 'yang.com'; ,‘yang.com 是 a.yang.com 和 b.yang.com 的主域名

4、postMessage
那么当两个主域名完全不同时,应该如何处理呢?来看看新方法 postMessage。

postMessage 原理
postMessage 是 HTML5 中新增方法,可实现跨域通信;

postMessage 并不是向服务器读写资源,只是向外发送消息而已;可以把它当做使用手机发送短信消息,仅此而已。

也就是:A 页面向 B 页面发送了一条消息,B 页面会接受到该消息,如果 B 页面需要该消息,则监听 message;否则无需关心该消息

postMessage 的使用
发送方:为目标元素添加事件处理程序,监听事件类型

接收方:为 window 添加事件处理程序,事件类型为 messag


postMessage 的注意点
这样就解除了降域的限制,可以将 postMessage 应用到各个不同的域之间,实现跨域访问。该方式比较安全,因为对方并不能直接操控我方资源,仅仅是发了一条消息,相当于指令,而最终操作权限仍在自己手中
虽然解决了降域的限制,但是:postMessage 是 window 的一个方法,话句话说:它的弱点是只能向 window 窗口发送消息。所以使用时至少要有一个 window 才行,postMessage 不可以向其他域名发送消息

(注意)
最后:降域和 postMessage 都是小众的降域方式,并不是经常使用,若有需求可按需选择


5、nginx代理跨域(服务器代理)

跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

#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;
    }
}

6、 WebSocket协议跨域

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

1.)前端代码:
<script>
var socket = io('http://www.domain2.com:8080');

// 连接成功处理
socket.on('connect', function() {
    // 监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server: ---> ' + msg);
    });

    // 监听服务端关闭
    socket.on('disconnect', function() {
        console.log('Server socket has closed.');
    });
});

document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>

Nodejs socket后台:
var http = require('http');
var socket = require('socket.io');

// 启http服务
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-type': 'text/html'
    });
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

// 监听socket连接
socket.listen(server).on('connection', function(client) {
    // 接收信息
    client.on('message', function(msg) {
        client.send('hello:' + msg);
        console.log('data from client: ---> ' + msg);
    });

    // 断开处理
    client.on('disconnect', function() {
        console.log('Client socket has closed.');
    });
});


7、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页面所有对象。

1.)a.html:(http://www.domain1.com/a.html)

<iframe id="iframe" src="http://www.domain2.com/b.html" style=""></iframe>
<script>
    var iframe = document.getElementById('iframe');

    // 向b.html传hash值
    setTimeout(function() {
        iframe.src = iframe.src + '#user=admin';
    }, 1000);
   
    // 开放给同域c.html的回调方法
    function onCallback(res) {
        alert('data from c.html ---> ' + res);
    }
</script>

2.)b.html:(http://www.domain2.com/b.html)

<iframe id="iframe" src="http://www.domain1.com/c.html" style=""></iframe>
<script>
    var iframe = document.getElementById('iframe');

    // 监听a.html传来的hash值,再传给c.html
    window.onhashchange = function () {
        iframe.src = iframe.src + location.hash;
    };
</script>

3.)c.html:(http://www.domain1.com/c.html)

<script>
    // 监听b.html传来的hash值
    window.onhashchange = function () {
        // 再通过操作同域a.html的js回调,将结果传回
        window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));
    };
</script>


8、window.name + iframe跨域
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

1.)a.html:(http://www.domain1.com/a.html)

var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe');

    // 加载跨域页面
    iframe.src = url;

    // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
    iframe.onload = function() {
        if (state === 1) {
            // 第2次onload(同域proxy页)成功后,读取同域window.name中数据
            callback(iframe.contentWindow.name);
            destoryFrame();

        } else if (state === 0) {
            // 第1次onload(跨域页)成功后,切换到同域代理页面
            iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';
            state = 1;
        }
    };

    document.body.appendChild(iframe);

    // 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)
    function destoryFrame() {
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
    }
};

// 请求跨域b页面数据
proxy('http://www.domain2.com/b.html', function(data){
    alert(data);
});
2.)proxy.html:(http://www.domain1.com/proxy....
中间代理页,与a.html同域,内容为空即可。

3.)b.html:(http://www.domain2.com/b.html)

<script>
    window.name = 'This is domain2 data!';
</script>
总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

编程小号
上一篇 2025-07-06 23:57
下一篇 2025-04-02 13:57

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/48097.html