【郑州-第132期】前端跨域问题有哪些常用的解决方式?

大家好,我是IT修真院郑州分院第一期的学员胡嘉杰,一枚正直纯洁善良的WEB前端程序员。

今天给大家分享一下,修真院官网JS任务5,深度思考中的知识点——前端跨域问题有哪些常用的解决方式?

1.背景介绍

为什么需要跨域?

受浏览器同源策略的限制,本域的js不能操作其他域的页面对象(比如DOM)。 但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。 所以我们要通过一些方法使本域的js能够操作其他域的页面对象或者使其他域的 js能操作本域的页面对象(iframe之间)。

这里需要明确的一点是: 所谓的域跟js的存放服务器没有关系, 比如baidu.com的页面加载了google.com的js, 那么此js的所在域是baidu.com而不是google.com。也就是说, 此时该js能操作baidu.com的页面对象,而不能操作google.com的页面对象。

2.知识剖析

1.跨域:指的是浏览器不能执行其他网站的脚本。 它是由浏览器的同源策略造成的, 是浏览器对javascript施加的安全限制。

2.同源策略:它是由Netscape提出的一个著名的安全策略。 同源是指,域名,协议,端口相同。浏览器执行javascript脚本时, 会检查这个脚本属于那个页面,如果不是同源页面,就不会被执行。

3.为什么script标签引入的文件不受同源策略的限制?: 因为script标签引入的文件内容是不能够被客户端的js获取到的, 不会影响到被引用文件的安全,所以没必要使script标签引入的文件遵循浏览器的同源策略。 而通过ajax加载的文件内容是能够被客户端js获取到的,所以ajax必须遵循同源策略, 否则被引入文件的内容会泄漏或者存在其他风险。

3.常见问题

有哪些常用的跨域方式?

4.解决方案

4.1使用iFrame访问另一个域。 然后再从另一个页面读取iFrame的内容。jquery等有一些封装。据说Firefox等可能不支持读取另一个iFrame的内容。

a)document.domain + iframe (domain 属性可返回下载当前文档的服务器域名,只有在主域相同的时候才能使用该方法)

b)location.hash + iframe(原理是利用location.hash来进行传值):假设域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息。

1) cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面

2) cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据

3) 同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值

注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe

c)window.name + iframe(window.name 的好处在于:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值【2MB】)

4.2CORS(背后的思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通, 从而决定请求或响应是应该成功,还是应该失败。)

4.3跨域 XMLHttpRequest 请求。

4.4通过JSONP跨域: 通过script标签引入一个js或者是一个其他后缀形式(如PHP,jsp等) 的文件,此文件返回一个js函数的调用,如返回JSONP_getUsers(["paco","john","lili"]), 也就是说此文件返回的结果调用了JSONP_getUsers函数,并且把["paco","john","lili"]传进去, 这个["paco","john","lili"]是一个用户列表。那么如果此时我们的页面中有一个JSONP_getUsers函数, 那么JSONP_getUsers就被调用到,并且传入了用户列表。此时就实现了在本域获取其他域数据的功能, 也就是跨域。

4.5 动态创建script: 这种方法其实是JSONP跨域的简化版,JSONP只是在此基础上加入了回调函数。

4.6服务器代理。

5.编码实战

5.1使用iFrame跨域

a)document.domain + iframe :

//在www.a.com/a.html中:

document.domain = 'a.com';

var ifr = document.createElement('iframe');

ifr.src = 'http://www.script.a.com/b.html';

ifr.display = none;

document.body.appendChild(ifr);

ifr.onload = function(){

var doc = ifr.contentDocument ||ifr.contentWindow.document;

//在这里操作doc,也就是b.html

ifr.onload = null;

};

//在www.script.a.com/b.html中:

document.domain = 'a.com';

b)location.hash + iframe:

//b.html页面的关键代码如下:

try {

parent.location.hash = 'data';

} catch (e) {

// ie、chrome的安全机制无法修改parent.location.hash,

var ifrproxy = document.createElement('iframe');

ifrproxy.style.display = 'none';

ifrproxy.src = "http://www.baidu.com/proxy.html#data";

document.body.appendChild(ifrproxy);

}

//proxy.html页面的关键代码如下:

//因为parent.parent(即baidu.com/a.html)

和baidu.com/proxy.html属于同一个域,

所以可以改变其location.hash的值

parent.parent.location.hash = self.location.hash.substring(1);

c)window.name + iframe:

//1) 创建a.com/cs1.html

//2) 创建a.com/proxy.html,并加入如下代码

function proxy(url, func) {

var isFirst = true;

ifr = document.createElement('iframe');

loadFunc = function () {

if (isFirst) {

ifr.contentWindow.location = 'http://a.com/cs1.html';

isFirst = false;

} else {

func(ifr.contentWindow.name);

ifr.contentWindow.close();

document.body.removeChild(ifr);

ifr.src = '';

ifr = null;

}

};

ifr.src = url;

ifr.style.display = 'none';

if (ifr.attachEvent) ifr.attachEvent('onload', loadFunc);

else ifr.onload = loadFunc;

document.body.appendChild(iframe);

}

proxy('http://www.baidu.com/', function (data) {

console.log(data);

});

//3) 在b.com/cs1.html中包含:

window.name = '要传送的内容';

5.3跨域 XMLHttpRequest 请求:

var xhr = new XMLHttpRequest();//建立xhr对象

if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {//等待回调

alert(xhr.statusText);

} else {

alert("Request was unsuccessful: " + xhr.status);

}

xhr.open("get", "example.php", false);

//请求的类型、请求的URL和是否异步发送

xhr.send(data);//参数

}

5.4通过JSONP跨域:

function handleResponse(response){

console.log('The responsed data is: '+response.data);

}

var script = document.createElement('script');

script.src = 'http://www.baidu.com/json/?callback=handleResponse';

document.body.insertBefore(script, document.body.firstChild);

/*handleResonse({"data": "zhe"})*/

//原理如下:

//当我们通过script标签请求时

//后台就会根据相应的参数(json,handleResponse)

//来生成相应的json数据(handleResponse({"data": "zhe"}))

//最后这个返回的json数据(代码)就会被放在当前js文件中被执行

//至此跨域通信完成

6.扩展思考

怎么选择跨域的方法?

跨域的方法很多,不同的应用场景我们都可以找到一个最合适的解决方案。 比如单向的数据请求,我们应该优先选择JSONP或者window.name, 双向通信优先采取location.hash, 在未与数据提供方达成通信协议的情况下我们也可以用server proxy的方式来抓取数据。

7.参考文献

参考一: 前端解决跨域问题的8种方案(最新最全)

参考二:解决前端跨域请求的几种方式

参考三:深入理解前端跨域方法和原理

8.更多讨论

怎么用NGINX跨域?


前端跨域问题有哪些常用的解决方式?_腾讯视频

------------------------------------------------------------------------------------------------------------------------

技能树.IT修真院

“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。

这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导。快来与我一起学习吧~

我的邀请码:64290793,或者你可以直接点击此链接:http://www.jnshu.com/login/1/64290793

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 什么是跨域? 2.) 资源嵌入:、、、等dom标签,还有样式中background:url()、@font-fac...
    电影里的梦i阅读 2,361评论 0 5
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    他在发呆阅读 822评论 0 0
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    w_zhuan阅读 510评论 0 0
  • 一:同源策略 1.what's this 所谓同源是指,域名,协议,端口相同。当浏览器运行一个JS脚本时会进行同源...
    吃茶叶蛋阅读 366评论 1 0
  • 我的孩子总是抱怨无聊,想让我放下所有的事情去跟他玩理解你的孩子,你自己和情形在我们生活的这个社会里,孩子们习惯了别...
    但雨泽阅读 468评论 0 0