ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

前端解决跨域问题

2021-06-18 17:04:14  阅读:204  来源: 互联网

标签:domain 跨域 前端 window 解决 document com example 页面


首先要了解浏览器跨域的问题源自哪里

浏览器跨域问题是源于浏览器的同源策略,,协议,域名,端口,三者有其中一个不一致就属于跨域。

浏览器的同源策略:
一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合。

URL网址的组成:
http://www.baidu.com:80/index.html?username=xxx&password=yyy#hash
协议://域名:端口 / 资源路径?查询字符串#hash

分类 基本内容
协议 http,https,ftp
主机名 localhost
端口 http默认端口:80,https默认端口:443

同源策略带来的麻烦:

ajax在不同域名下的请求无法实现。

Access to fetch at ‘xxx’ from origin ‘xxx’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

如下所示:
在这里插入图片描述

解决跨域的六种办法:

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

JSONP应用的技巧:
在HTML标签里,一些标签比如script、img这样的获取资源的标签是没有跨域限制的。

2. CORS跨域
后端修改请求头
header(‘Access-Control-Allow-Origin:*’);允许访问的网址
header(‘Access-Control-Allow-Method:POST,GET’);允许访问的方式

3. nginx反向代理
www.baidu.com/index.html需要调用www.sina.com/server.php,可以写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,然后再返回给index.html

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>
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" onl oad = "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" onl oad = "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];
           var isEmpty = true;
           for(var t in this.eventQueue){
               isEmpty = false;
           }
           if(isEmpty){
               this.id = 0;
           }
       }
   }.bind(this);
}

标签:domain,跨域,前端,window,解决,document,com,example,页面
来源: https://blog.51cto.com/u_15275953/2924573

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有