各类前端实现跨域的方法

本文介绍了跨域的概念,即浏览器请求不同域名资源时,域名、端口、协议任一不同即为跨域。同时阐述了多种跨域问题的解决方法,如jsonp跨域、nginx反向代理、PHP端修改header、document.domain、window.name、postMessage等,还提及vue项目和本地node服务器的跨域处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考网站

Nginx 轻松搞定跨域问题! - china_coding - 博客园

什么是跨域?如何解决跨域问题?_飞扬_柳絮的博客-优快云博客_跨域问题

浅析JSONP-解决Ajax跨域访问问题 - Jerry Tian - 博客园

什么是跨域?

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域 
域名: 
 主域名不同 百度一下,你就知道 –>新浪首页 
 子域名不同 http://www.666.baidu.com/index.html –>http://www.555.baidu.com/test.js 
 域名和域名ip 百度一下,你就知道 –>http://180.149.132.47/test.js 
端口: 
 http://www.baidu.com:8080/index.html–http://www.baidu.com:8081/test.js 
协议: 
 http://www.baidu.com:8080/index.html–https://www.baidu.com:8080/test.js 
备注: 
 1、端口和协议的不同,只能通过后台来解决 
 2、localhost和127.0.0.1虽然都指向本机,但也属于跨域

如何解决跨域问题?

1、jsonp跨域 

工作原理:由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。若要跨域请求出于安全性考虑是不行的,但是我们发现,Web页面上调用js文件时则不受是否跨域的影响,而且拥有”src”这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>,这时候,聪明的程序猿就想到了变通的方法,如果要进行跨域请求, 通过使用html的script标记来进行跨域请求,利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。即在跨域的服务端生成JSON数据,然后包装成script脚本回传


JSONP(JSON with Padding:填充式JSON),应用JSON的一种新方法, 
JSON、JSONP的区别: 
 1、JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用) 
 2、JSONP 只支持get请求、不支持post请求 
 (类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)

2、nginx反向代理: 
  www.baidu.com/index.html需要调用www.sina.com/server.php,可以写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,然后再返回给index.html (移动端调试常用
3、PHP端修改header 

跨域主要涉及4个响应头:

  • Access-Control-Allow-Origin 用于设置允许跨域请求源地址 (预检请求和正式请求在跨域时候都会验证)
  • Access-Control-Allow-Headers 跨域允许携带的特殊头信息字段 (只在预检请求验证)
  • Access-Control-Allow-Methods 跨域允许的请求方法或者说HTTP动词 (只在预检请求验证)
  • Access-Control-Allow-Credentials 是否允许跨域使用cookies,如果要跨域使用cookies,可以添加上此请求响应头,值设为true(设置或者不设置,都不会影响请求发送,只会影响在跨域时候是否要携带cookies,但是如果设置,预检请求和正式请求都需要设置)。不过不建议跨域使用(项目中用到过,不过不稳定,有些浏览器带不过去),除非必要,因为有很多方案可以代替。

  
4、document.domain(设置主域,同域下的资源可以共用 
跨域分为两种,一种xhr不能访问不同源的文档,另一种是不同window之间不能进行交互操作
  document.domain主要是解决第二种情况,且只能适用于主域相同子域不同的情况; 
  document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com中某个文档的document.domain可以设成a.b.example.com、b.example.com 、example.com中的任意一个,但是不可以设成c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。 
兼容性:所有浏览器都支持; 
优点: 
 可以实现不同window之间的相互访问和操作; 
缺点: 
 只适用于父子window之间的通信,不能用于xhr; 
 只能在主域相同且子域不同的情况下使用; 
使用方式: 
 不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:

<script type="text/javascript">
    function test(){
        var iframe = document.getElementById('ifame');
        var win = document.contentWindow;//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
        var doc = win.document;//这里获取不到iframe里的document对象
        var name = win.name;//这里同样获取不到window对象的name属性
    }
</script>
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>

这个时候,document.domain就可以派上用场了,我们只要把http://www.example.com/a.html 和 http://example.com/b.html两个页面的document.domain都设成相同的域名就可以了。 
1.在页面 http://www.example.com/a.html 中设置document.domain:

<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
    document.domain = 'example.com';//设置成主域
    function test(){
        alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
    }
</script>

2.在页面 http://example.com/b.html 中也设置document.domain:

<script type="text/javascript">
    document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
</script>

5、window.name 
关键点:window.name在页面的生命周期里共享一个window.name; 
兼容性:所有浏览器都支持; 
优点: 
 最简单的利用了浏览器的特性来做到不同域之间的数据传递; 
 不需要前端和后端的特殊配制; 
缺点: 
 大小限制:window.name最大size是2M左右,不同浏览器中会有不同约定; 
 安全性:当前页面所有window都可以修改,很不安全; 
 数据类型:传递数据只能限于字符串,如果是对象或者其他会自动被转化为字符串,如下; 
 这里写图片描述
使用方式:修改window.name的值即可; 
6、postMessage 
关键点: 
 postMessage是h5引入的一个新概念,现在也在进一步的推广和发展中,他进行了一系列的封装,我们可以通过window.postMessage的方式进行使用,并可以监听其发送的消息; 
兼容性:移动端可以放心用,但是pc端需要做降级处理 
优点 
 不需要后端介入就可以做到跨域,一个函数外加两个参数(请求url,发送数据)就可以搞定; 
 移动端兼容性好; 
缺点 
 无法做到一对一的传递方式:监听中需要做很多消息的识别,由于postMessage发出的消息对于同一个页面的不同功能相当于一个广播的过程,该页面的所有onmessage都会收到,所以需要做消息的判断; 
安全性问题:第三方可以通过截获,注入html或者脚本的形式监听到消息,从而能够做到篡改的效果,所以在postMessage和onmessage中一定要做好这方面的限制; 
 发送的数据会通过结构化克隆算法进行序列化,所以只有满足该算法要求的参数才能够被解析,否则会报错,如function就不能当作参数进行传递; 
使用方式:通信的函数,sendMessage负责发送消息,bindEvent负责消息的监听并处理,可以通过代码来做一个大致了解;

Storage.prototype.sendMessage_ = function(type, params, fn) {
    if (this.topWindow) {
        this.handleCookie_(type, params, fn);
        return;
    }
    var eventId = this.addToQueue_(fn, type);
    var storageIframe = document.getElementById('mip-storage-iframe');
    var element = document.createElement("a");
    element.href = this.origin;
    var origin = element.href.slice(0, element.href.indexOf(element.pathname) + 1);
    storageIframe.contentWindow.postMessage({ // 连接窗口,传输信息
        type: type,
        params: params,
        eventId: eventId
    }, origin);
}
Storage.prototype.bindEvent_ = function() {
    window.onmessage = function (res) {
        // 判断消息来源,窗口是否来自父级窗口
        if (window == res.source.window.parent &&
            res.data.type === this.messageType.RES &&
            window.location.href.match(res.origin.host).length > 0) {
            var fn = this.eventQueue[res.data.eventId];
            fn && fn();
            delete this.eventQueue[res.data.eventId];
            // reset id
            var isEmpty = true;
            for (var t in this.eventQueue) {
                isEmpty = false;
            }
            if (isEmpty) {
                this.id = 0;
            }
        }
    }.bind(this);
}

7vue项目可通过$axios进行配置达到跨域,具体查看解决Axios跨域问题(Axios跨域问题解决方案)_Moshow郑锴的博客-优快云博客_axios 跨域

  • 设置baseURL
  • 设置proxy代理

8本地node服务器转发跨域请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值