js__JSONP__跨域

1: 什么是同源策略

  • 最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源",所谓"同源"指的是"三个相同".
    协议相同
    域名相同
    端口相同

  • 举例来说:
    http://www.example.com/dir/page.html
    这个网址协议是http://,域名是www.example.com,端口是80(默认端口可以省略),它的同源情况如下.
    http://www.example.com/dir2/other.html:同源
    http://example.com/dir/other.html:不同源(域名不同)
    http://v2.www.example.com/dir/other.html:不同源(域名不同)
    http://www.example.com:81/dir/other.html:不同源(端口不同)
    https://www.example.com:81/dir/other.html:不同源(https协议不同)

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

  • 跨域出现的原因
    JavaScript出于安全方面的考虑,不允许一个网页访问一个非同源的网页,即2个网址的协议相同,域名相同,端口相同其中任意一个不同就是非同源.
  • 概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域。
    比如:有一个Ajax的var xhr=new XMLHttpRequest()的xhr对象,在a网址里发生请求到一个非同源的b网址,会请求的报错.
不跨域会出现图片的的报错
  • 跨域就是为了解决这个问题,实现非同源网页之间的数据传输和通信.

跨域常见方式

  • JSONP(JSON with Padding 填充式JSON 或参数式JSON)

  • CORS(Cross-Origin Resource Sharing,跨源资源共享)

  • HTML5的window.postMessage
    window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
    window.postMessage允许两个窗口/帧之间跨域发送数据消息。从本质上讲,window.postMessage是一个跨域的无服务器垫片的Ajax。

  • 降域: document.domain
    使用条件
    有其他页面 window 对象的引用,
    二级域名相同,
    协议相同,
    端口相同

//在页面 http://www.example.com/a.html 中设置document.domain:
<iframe src="example.com/b.html" id="iframe" onload="test()"></iframe>
    <script>
        document.domain='example.com';//设置成主域
        function test(){
            alert(document.getElementById('iframe').contentWindow);
        }
    </script>
//在页面 http://example.com/b.html中也设置document.domain
<script>
        document.domain='example.com';//在iframe载入的这个页面也设置 document.domain与主页面相同
</script>
//而且是必须的,虽然这个文档的domain就是example.com,但是还是必须显示的设置document.domain的值

3: JSONP 的原理是什么

  • JSONP (JSON with Padding)是一个简单高效的跨域方式,html中的script标签可以加载并执行其他域的JavaScript,于是我们可以通过script标记来动态加载其他域的资源,例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP是非常合适的选择。

  • .css,.js,图片的引用和jsonp跨域拿到js方法有什么区别 ?
    相同点:
    在html里.js,图片的引用和jsonp拿到js的方法是一样的,都是从服务器那到js文件然后插入到html里.
    不同:
    只不过出发点是不一样,前者是加载资源,后者为了跨域拿后台返回的js.
    jsonp还多了一个回调,区别是出发点和应用方法不同,但都有从服务器返回的资源.

4: CORS是什么

  • CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通.CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败.跨域后浏览器不会返回数据.

  • **简单请求 **

浏览器将CORS请求分成两类:简单请求(simple request)和
简单请求条件
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
凡是不同时满足上面两个条件,就属于非简单请求

  • 使用
    在服务器后台设置header属性Access-Control-Allow-Origin
    它的值是请求时Origin字段的值或者 * ,* 表示接受任意域名的请求。
app.get('/getNews', function(req, res){

    var news = [
        "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
    ]
    var data = [];
    for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
        news.splice(index, 1);
    }
    res.header("Access-Control-Allow-Origin", "http://a.jrg.com:8080"); //代表只接受http://a.jrg.com:8080网址的请求
    //res.header("Access-Control-Allow-Origin", "*"); //*表示接受任意域名的请求

    res.send(data);
})
  • 非简单请求
    是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
    非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight).
    浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
  • CORS与JSONP的比较
    CORS与JSONP的使用目的相同,但是比JSONP更强大,但CORS不支持IE6.7.8.
    JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据.

跨域问题
跨域10种方式

5: 演示三种常用以上跨域的解决方式

  • jsonp
    参考阮一峰

  • 先在客户端上设置 新 Hosts
    127.0.0.1 a.jrg.com
    127.0.0.1 b.jrg.com
    127.0.0.1 jrg.com

router.js


app.get('/getNews', function(req, res){
var news = [
'我没有特别的才能,只有强烈的好奇心。永远保持好奇心的人是永远进步的人。——爱因斯坦',

'爱因斯坦认为他之所以取得成功,原因在于他具有狂热的好奇心.',
'求知欲,好奇心这是人的永恒的,不可改变的特性。哪里没有求知欲,哪里便没有学校。——苏霍姆林斯基',

'孩子提出的问题越多,那么他在童年早期认识周围的东西也就愈多,在学校中越聪明,眼睛愈明,记忆力愈敏锐。要培养自己孩子的智力,那你就得教给他思考。——苏霍姆林斯基',

'我想起了自己小学的学习经历,终于理解了为什么小时候成绩好,我那时候确实好奇心非常强烈.',
'人的内心里有一种根深蒂固的需要——总想感到自己是发现者、研究者、探寻者。在儿童的精神世界中,这种需求特别强烈。但如果不向这种需求提供养料,即不积极接触事实和现象,缺乏认识的乐趣,这种需求就会逐渐消失,求知兴趣也与之一道熄灭。(苏霍姆林斯基)',

'生活的全部意义在于无穷地探索尚未知道的东西,在于不断地增加更多的知识。——左拉'
    ]
    var data = [];
    for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
        news.splice(index, 1);//把data数组里已经有的元素从news数组里删除,保证不重复上一步拿到的新闻
    }
    var cb = req.query.callback
    if(cb){
        res.send(cb + '('+ JSON.stringify(data) + ')');
    }else{
        res.send(data);
    }   
})

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>news</title>
<style>
  .container{
    width: 900px;
    margin: 0 auto;
  }
</style>
</head>
<body>
  <div class="container">
    <ul class="news">
      <li>我没有特别的才能,只有强烈的好奇心 ——爱因斯坦</li>
      <li>我没有特别的才能,只有强烈的好奇心 ——爱因斯坦</li> 
      <li>我没有特别的才能,只有强烈的好奇心 ——爱因斯坦</li>
    </ul>
    <button class="change">点我换一组</button>
  </div>
  
<script>
  
  $('.change').addEventListener('click', function(){
    var script = document.createElement('script');
    script.src = 'http://gaygay.com:8080/getNews?callback=appendHtml';//必须是'http://xxx.com:8080/的形式
   
    document.head.appendChild(script);
    document.head.removeChild(script);
  })
  
  function appendHtml(news){
    var html = '';
    for( var i=0; i<news.length; i++){
      html += '<li>' + news[i] + '</li>';
    }
    console.log(html);
    $('.news').innerHTML = html;
  }
  function $(id){//$函数,发请求前和点击换一组都调用.传入参数,直接返回.
    return document.querySelector(id);//替换$(id)为document.querySelector(id),因为浏览器不支持jquery库
  }
</script>

</body>

</html>

结合上面的案例说下jsonp的本质:


后台判断:
 var cb = req.query.callback
    if(cb){
        res.send(cb + '('+ JSON.stringify(data) + ')');
    }

场景:
A网访问跨域的B网资源:
在A网通过给script标签的src赋值一个网址.
例子: var script = document.createElement('script');
    script.src = 'http://gaygay.com:8080/getNews?callback=appendHtml'

这个网址带有回调的方法名.加载script脚本到B网页,B网页发回消息去调用在A网页脚本里定义的回调函数.callback.

6.CORS案例

QQ20170512-220224-HD.gif
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>news</title>
<style>
 .container{
   width: 900px;
   margin: 0 auto;
 }
</style>
</head>
<body>
 <div class="container">
   <ul class="news">
     <li>CORS练习</li>
     <li>男双力争会师决赛 </li> 
     <li>女排将死磕巴西!</li>
   </ul>
   <button class="change">换一组</button>
 </div>
 
<script>
 
 $('.change').addEventListener('click', function(){
   var xhr = new XMLHttpRequest();
   xhr.open('get', 'http://b.jrg.com:8080/getNews', true);
   xhr.send();
   xhr.onreadystatechange = function(){
     if(xhr.readyState === 4 && xhr.status === 200){
       appendHtml( JSON.parse(xhr.responseText) )
     }
   }
   window.xhr = xhr//why?
 })
 function appendHtml(news){
   var html = '';
   for( var i=0; i<news.length; i++){
     html += '<li>' + news[i] + '</li>';
   }
   console.log(html);
   $('.news').innerHTML = html;
 }
 function $(id){
   return document.querySelector(id);
 }
</script>
</html>

router.js


app.get('/getNews', function(req, res){

    var news = [
        "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
        "正直播柴飚/洪炜出战 男双力争会师决赛",
        "女排将死磕巴西!郎平安排男陪练模仿对方核心",
        "没有中国选手和巨星的110米栏 我们还看吗?",
        "中英上演奥运金牌大战",
        "博彩赔率挺中国夺回第二纽约时报:中国因对手服禁药而丢失的奖牌最多",
        "最“出柜”奥运?同性之爱闪耀里约",
        "下跪拜谢与洪荒之力一样 都是真情流露"
    ]
    var data = [];
    for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
        news.splice(index, 1);
    }
    res.header("Access-Control-Allow-Origin", "http://jrg.com:8080"); 
    //res.header("Access-Control-Allow-Origin", "*"); 
    res.send(data);

7.document.domain降域

QQ20170513-104421-HD.gif

情景:a.html里面嵌入iframe元素,且这个iframe是<iframe src="http://b.jrg.com:8080/b.html" frameborder="0" ></iframe>,而b.html就是个其中src规定显示在 iframe 中的文档的地址,也是绝对 URL - 指向其他站点(比如 src="www.example.com/index.html"),这里是个非同源的b.html

//a.html文件

<html>
<style>
  .ct{
    width: 910px;
    margin: auto;
  }
  .main{
    float: left;
    width: 450px;
    height: 300px;
    border: 1px solid #ccc;
  }
  .main input{
    margin: 20px;
    width: 200px;
  }
  .iframe{
    float: right;
  }
  iframe{
    width: 450px;
    height: 300px;
    border: 1px dashed #ccc;
  }
</style>

<div class="ct">
  <h1>使用降域实现跨域</h1>
  <div class="main">
    <input type="text" placeholder="http://a.jrg.com:8080/a.html">
  </div>

  <iframe src="http://b.jrg.com:8080/b.html" frameborder="0" ></iframe>

</div>


<script>
//URL: http://a.jrg.com:8080/a.html
document.querySelector('.main input').addEventListener('input', function(){
  console.log(this.value);
  window.frames[0].document.querySelector('input').value = this.value;
})

document.domain = "jrg.com"//降域关键代码
</script>
</html>


//b.html
<html>
<style>
    html,body{
        margin: 0;
    }
    input{
        margin: 20px;
        width: 200px;
    }
</style>

    <input id="input" type="text"  placeholder="http://b.jrg.com:8080/b.html">
<script>

 
document.querySelector('#input').addEventListener('input', function(){
    window.parent.document.querySelector('input').value = this.value;
})
document.domain = 'jrg.com';
</script>
</html>


  • window.frames[0].postMessage
//a.html文件

<html>
<style>
    .ct{
        width: 910px;
        margin: auto;
    }
    .main{
        float: left;
        width: 450px;
        height: 300px;
        border: 1px solid #ccc;
    }
    .main input{
        margin: 20px;
        width: 200px;
    }
    .iframe{
        float: right;
    }
    iframe{
        width: 450px;
        height: 300px;
        border: 1px dashed #ccc;
    }
</style>

<div class="ct">
    <h1>使用postMessage实现跨域</h1>
    <div class="main">
        <input type="text" placeholder="http://a.jrg.com:8080/a.html">
    </div>

    <iframe src="http://localhost:8080/b.html" frameborder="0" ></iframe>

</div>


<script>
//URL: http://a.jrg.com:8080/a.html
$('.main input').addEventListener('input', function(){
    console.log(this.value);
    window.frames[0].postMessage(this.value,'*');//window.frames[0]是window子窗口的第一个.*代表任意地址

})
window.addEventListener('message',function(e) {
        $('.main input').value = e.data
    console.log(e.data);
});

//
window.addEventListener('message',function(e){
  $('.mian input').value = e.data;
})


function $(id){
    return document.querySelector(id);
}
</script>
</html>
//b.html文件:即被内嵌的iframe链接文档url.
<html>
<style>
    html,body{
        margin: 0;
    }
    input{
        margin: 20px;
        width: 200px;
    }
</style>

    <input id="input" type="text"  placeholder="http://b.jrg.com:8080/b.html">
<script>

 
 //传出数据到内嵌此窗口的父窗口即a.html.
$('#input').addEventListener('input', function(){
    window.parent.postMessage(this.value, '*');//
    //返回当前窗口的父窗口对象.如果一个窗口没有父窗口,则它的 parent 属性为自身的引用.
    //如果当前窗口是一个 <iframe>, <object>, 或者 <frame>,则它的父窗口是嵌入它的那个窗口
})

//接收信息
window.addEventListener('message',function(e) {
        $('#input').value = e.data
    console.log(e.data);
});
function $(id){
    return document.querySelector(id);
}   
</script>
</html>

跨域实例的代码参考

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

推荐阅读更多精彩内容

  • Section1、为什么要跨域? 自古以来(1995年起),为了用户的信息安全,浏览器就引入了同源策略。那么同源策...
    qhaobaba阅读 376评论 0 0
  • Section1、为什么要跨域? 自古以来(1995年起),为了用户的信息安全,浏览器就引入了同源策略。那么同源策...
    不去解释阅读 540评论 0 0
  • 1.什么是同源策略 1.要了解同源策略,我们必须先知道源即orgin 以百度页面为例,谷歌浏览器打开控制台:输入l...
    GarenWang阅读 1,437评论 2 8
  • 现代人就像一个贝壳 紧紧闭着就是不肯打开 因为里面太柔软、太怕受伤 而只有“美”才会让它不防御 让它放下戒备心,让...
    SeanQD阅读 631评论 0 1
  • 上篇的彩蛋大家看出来了吧。没错,那篇武安君的遗书是我瞎编的。 继续王翦的故事。 王翦封侯 类似的情形,也曾发生在王...
    三角猫阅读 1,329评论 0 11