进阶13-常见的跨域解决方案

  • 什么是同源策略

同源策略是指浏览器处于安全方面的考虑只允许本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读取对方的资源。
其中同源是指:
- 协议相同,比如http://lalala.comhttps://lalala.com不属于同源
- 域名相同,比如http://b.lalala.comhttp://a.lalala.com不属于同源
- 端口相同,比如http://lalala.com:8082http://lalala.com不属于同源

  • 什么是跨域?跨域有几种实现形式

跨域是指不同域之间的接口进行交互;
常见的跨域解决方式有如下几种:
- ### JSONP
JSONP是JSON with Padding的简写,是应用JSON的一种方法,JSONP看起来 与JSON差不多,只不过是被包含在回调函数中的JSON。JSONP由两部分组成,回调函数和JSON数据,回调函数是当响应到来时应该在页面中调用的函数(这个函数会在页面中提前定义好)。所以JSONP的原理是利用<script>标签可以不受限制地从其他域加载资源的能力动态创建<script>标签,然后在这个标签中向指定url请求JSONP数据,当数据被服务端传回页面时,回调函数把JSON数据传入并执行,从而达到从其他域直接访问响应文本的目的。例如:
//事件处理函数,当需要去访问其他域的文本时触发 function eventHandler() { var script = document.createElement('script'); script.src = 'http://otherDomain.com/json/?callback=JSONHandler' document.body.appendChild(script); } //回调函数,当服务端传回类似'JSONHandler' + '(' + json ')'的数据时调用 function JSONHandler(json) {}
下面是一个简单通过JSONP实现的猜数例子:
客户端代码:
<!doctype html> <html> <head> </head> <body> <div id='ctn'> <input type="input" id="number" placeholder="1到100的整数" > <br> <button id="guess">猜吧</button> </div> <script> function $(str) { return document.querySelector(str); } var input = $('#number'); var guess = $('#guess'); //事件处理函数 guess.addEventListener( 'click', function() { var guessNumber = parseInt(input.value); if(isNaN(guessNumber)) { alert('老铁,输个数字过来好吗');return;} var script = document.createElement('script'); script.src = 'http://localhost:8080/guessNumber?callback=xxx&number=' + guessNumber; document.body.appendChild(script); }) //回调函数 function xxx(json) { div = document.createElement('div'); div.innerText = '你猜的数字是:' + parseInt(input.value) + ',' + json[parseInt(input.value)]; ctn.appendChild(div); } </script> </body> </html>
服务端代码:
var theNumber = 77; app.get('/guessNumber', function(req, res){ var data = {}; var guessNumber = parseInt(req.query.number); if(guessNumber > theNumber) { data[guessNumber] = '大了'; } else if(guessNumber < theNumber) { data[guessNumber] = '小了'; } else { data[guessNumber] = '中了'; } //返回JSONP var cb = req.query.callback; console.log(cb); if(cb) { let tmp = cb + '('+ JSON.stringify(data) +')' console.log(tmp); res.send(tmp); } else { res.send(data); } })
下图为本地开启server-mock的效果图:

image.png

  • CROS

CROS(Cross-Origin Resource Sharing,跨域资源共享)是W3C定义的一个跨域资源共享规范,规定了在必须访问跨域西原始浏览器与服务器应该如何沟通。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

比如一个简单请求,它没有自定义头部,在发送之前需要给它附加一个额外的`Origin`头部,其中包含请求页面的源信息(协议、域名、端口),以便服务器根据这个头部信息来决定是否给予响应;如果服务器认为该请求可以接受,则在响应报文的首部中添加`Access-Control-Allow-Origin`的头,其值与请求报文中`Origin`头的值一致,或者为`*`表示接受所有域的请求。这里的`Origin`头的发送与是否跨域无关。
其中简单请求的定义如下:
>只要同时满足以下两大条件,就属于简单请求
1.  请求方法是以下三种方法之一:
    - HEAD
    - GET
    - POST
2. HTTP的头信息不超出以下几种字段:
    - Accept
    - Accept-Language
    - Content-Language
    - Last-Event-ID

其中Content-Type:只限于三个值application/x-www-form-urlencoded、 multipart/form-data、text/plain

若是一个非简单请求(相对简单请求而言),则在正式发送请求报文之前需要通过`OPTIONS`方法发送一个预检报文,报文首部有`Access-Control-request-method`头和`Access-Control-request-Headers`头,用以告知服务器实际请求所使用的HTTP方法和携带的自定义首部,然后服务器根据这些值判断是否接受该请求;然后返回响应报文,在响应报文中添加`Access-Control-Allow-Methods`头和`Access-Control-Allow-Headers`头作为请求报文中对应头的回复。
  • 降域

// 降域方式
// 修改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>
// 子窗口
<script type="text/javascript">
    document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
</script>
  • postMessage

window.postMessage(message,targetOrigin)方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。

调用`postMessage`方法的`window`对象是指要接收消息的那一个`window`对象,该方法的第一个参数`message`为要发送的消息,类型只能为字符串;第二个参数`targetOrigin`用来限定接收消息的那个`window`对象所在的域,如果不想限定域,可以使用通配符 *  。需要接收消息的`window`对象,可是通过监听自身的`message`事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。

更多请参看:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
http://zqdevres.qiniucdn.com/data/20160412110843/index.html
http://www.cnblogs.com/2050/p/3191744.html

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

推荐阅读更多精彩内容