读书笔记,不就是跨域么

JSONProxy – 获取跨域json数据工具

2015/07/10 · JavaScript
· JSON,
JSONProxy

原文出处: 韩子迟   

JSONProxy是一款很好的得到json数量的代办网站,“Enables
cross-domain requests to any JSON
API”。当您苦于不可以跨域获取json数据时,不妨一试,说不定能两全其美。

譬如那位情人,想通过ajax获取必应的每日一图的url(是不是足以经过ajax获取“Bing天天一图”?)很明确,那几个ajax是跨域的,直接获得会因为跨域报错;服务端也终将不会有对你本地localhost的“Access-Control-Allow-Origin”的设置,所以CORS策略也是万分的;因为是个json数据,没有办法名包裹,所以jsonp也是丰硕。楼主暂时还没接触过任何的跨域方法,倘诺要自身去赢得url,只好通过服务端的代码,服务端去获取json数据,然后index页面去ajax请求服务端获取的json数据(此时index页面和服务端同源),代码量扩张,而要做的仅仅只是获取一个json数据啊!那时JSONProxy就帮您做好了服务端的行事,是否很爽!

别慌,不就是跨域么!

2017/12/27 · 基本功技术 ·
跨域

初稿出处:
Neal_yang   

前端开发中,跨域使我们日常碰着的一个标题,也是面试中平日被问到的有的难点,所以,那里,咱们做个小结。小小意思,不足担心

跨域:掘金地址——

作者:Neal_yang

github.com/Nealyang/YOU-SHOULD-KNOW-JS/blob/master/doc/basic_js/JavaScript中的跨域总括.md

Easy: JSONP

原生的JavaScript:

XHTML

<script> function myCallback(data){ console.log(data); }
</script> <script
src=”;

1
2
3
4
5
6
<script>
  function myCallback(data){
    console.log(data);
  }
</script>
<script src="https://jsonp.afeld.me/?callback=myCallback&url=http://jsonview.com/example.json"></script>

myCallback函数里的data就是回到的json数据了。很明显,服务器会帮你去哀告你必要的json数据,然后装进在您设置的回调函数名中,那时要专注的代码中的灰色两处要保持一致,url后跟的就是须求的json数据地址。

本来JQuery封装好的点子尤其简约:

XHTML

<script>
$.getJSON(”,
function(data){ console.log(data); }); </script>

1
2
3
4
5
<script>
  $.getJSON(‘https://jsonp.afeld.me/?callback=?&url=http://jsonview.com/example.json’, function(data){
    console.log(data);
  });
</script>

怎样是跨域

跨域,是指浏览器不可能实施此外网站的本子。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全范围。

同源策略限制了一下表现:

Cookie、LocalStorage 和 IndexDB 无法读取
DOM 和 JS 对象不可能得到
Ajax请求发送不出来

另一篇学习地点:

 

Easier: Cross-domain AJAX (CORS)

比jsonp更简短的形式是CORS(好呢,也没不难到哪去啊…)

XHTML

<script>
$.get(”,
function(data){ console.log(data); }); </script>

1
2
3
4
5
<script>
  $.get(‘https://jsonp.afeld.me/?url=http://jsonview.com/example.json’, function(data){
    console.log(data);
  });
</script>

那回是真的地发送了ajax请求了,为啥跨域了还是可以请求?因为服务端设置好了。

亚洲必赢官网 1

而请求的json数据也是服务端帮您取得的。也就是说,客户端发送请求,服务端解析呼吁的url,然后服务器作为代理发送http请求去央浼json数据(那时不存在客户端跨域),再重临给客户端作为回调的参数。

广阔的跨域场景

所谓的同源是指,域名、协议、端口均为同一。

JavaScript

调用
非跨域 调用
跨域,主域差别
调用
跨域,子域名分裂 调用
跨域,端口差距
调用
跨域,协议不相同 localhost 调用 127.0.0.1
跨域

1
2
3
4
5
6
7
8
9
10
11
http://www.nealyang.cn/index.html 调用   http://www.nealyang.cn/server.php  非跨域
 
http://www.nealyang.cn/index.html 调用   http://www.neal.cn/server.php  跨域,主域不同
 
http://abc.nealyang.cn/index.html 调用   http://def.neal.cn/server.php  跨域,子域名不同
 
http://www.nealyang.cn:8080/index.html 调用   http://www.nealyang.cn/server.php  跨域,端口不同
 
https://www.nealyang.cn/index.html 调用   http://www.nealyang.cn/server.php  跨域,协议不同
 
localhost   调用 127.0.0.1 跨域

跨域的解决办法
jsonp跨域

jsonp跨域其实也是JavaScript设计情势中的一种代理情势。在html页面中通过相应的竹签从差距域名下加载静态资源文件是被浏览器允许的,所以大家可以通过这几个“犯罪漏洞”来拓展跨域。一般,我们得以动态的创立script标签,再去央求一个带参网址来兑现跨域通讯

读书笔记,不就是跨域么。JavaScript

//原生的贯彻形式 let script = document.createElement(‘script’);
script.src =
”;
document.body.appendChild(script); function callback(res) {
console.log(res); }

1
2
3
4
5
6
7
8
9
10
//原生的实现方式
let script = document.createElement(‘script’);
 
script.src = ‘http://www.nealyang.cn/login?username=Nealyang&callback=callback’;
 
document.body.appendChild(script);
 
function callback(res) {
  console.log(res);
}

当然,jquery也支撑jsonp的兑现格局

JavaScript

$.ajax({ url:”, type:’GET’,
dataType:’jsonp’,//请求格局为jsonp jsonpCallback:’callback’, data:{
“username”:”Nealyang” } })

1
2
3
4
5
6
7
8
9
$.ajax({
    url:’http://www.nealyang.cn/login’,
    type:’GET’,
    dataType:’jsonp’,//请求方式为jsonp
    jsonpCallback:’callback’,
    data:{
        "username":"Nealyang"
    }
})

固然那种格局极度好用,不过一个最大的后天不足是,只可以够完结get请求
document.domain + iframe 跨域

那种跨域的艺术最要紧的是讲求主域名相同。什么是主域名相同呢?
www.nealyang.cn aaa.nealyang.cn ba.ad.nealyang.cn
那三个主域名都是nealyang.cn,而主域名分歧的就不可以用此方法。

倘使近期a.nealyang.cn 和 b.nealyang.cn 分别对应指向不一致ip的服务器。

a.nealyang.cn 下有一个test.html文件

JavaScript

<!DOCTYPE html> <html lang=”en”> <head> <meta
charset=”UTF-8″> <title>html</title> <script
type=”text/javascript” src = “jquery-1.12.1.js”></script>
</head> <body> <div>A页面</div> <iframe style
= “display : none” name = “iframe1” id = “iframe”
src=”” frameborder=”0″></iframe>
<script type=”text/javascript”> $(function(){ try{ document.domain
= “nealyang.cn” }catch(e){} $(“#iframe”).load(function(){ var jq =
document.getElementById(‘iframe’).contentWindow.$
jq.get(” console.log(data);
}); }) }) </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>html</title>
    <script type="text/javascript" src = "jquery-1.12.1.js"></script>
</head>
<body>
    <div>A页面</div>
    <iframe
    style = "display : none"
    name = "iframe1"
    id = "iframe"
    src="http://b.nealyang.cn/1.html" frameborder="0"></iframe>
    <script type="text/javascript">
        $(function(){
            try{
                document.domain = "nealyang.cn"
            }catch(e){}
            $("#iframe").load(function(){
                var jq = document.getElementById(‘iframe’).contentWindow.$
                jq.get("http://nealyang.cn/test.json",function(data){
                    console.log(data);
                });
            })
        })
    </script>
</body>
</html>

运用 iframe 加载 其余域下的文书(nealyang.cn/1.html), 同时
document.domain 设置成 nealyang.cn ,当 iframe 加载达成后就可以收获
nealyang.cn 域下的大局对象, 此时尝试着去哀告 nealyang.cn 域名下的
test.json (此时可以请求接口),就会意识数目请求战败了~~
惊不惊喜,意不意外!!!!!!!

多少请求战败,目标绝非达成,自然是还少一步:

JavaScript

<!DOCTYPE html> <html lang=”en”> <head> <meta
charset=”UTF-8″> <title>html</title> <script
type=”text/javascript” src = “jquery-1.12.1.js”></script>
<script type=”text/javascript”> $(function(){ try{ document.domain
= “nealyang.com” }catch(e){} }) </script> </head>
<body> <div id = “div1”>B页面</div> </body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>html</title>
    <script type="text/javascript" src = "jquery-1.12.1.js"></script>
    <script type="text/javascript">
        $(function(){
            try{
                document.domain = "nealyang.com"
            }catch(e){}
        })
    </script>
</head>
<body>
    <div id = "div1">B页面</div>
</body>
</html>

那时候在展开刷新浏览器,就会意识数目这次真正是马到功成了~
window.name + iframe 跨域

window.name属性可安装或者再次来到存放窗口名称的一个字符串。他的神器之处在于name值在分歧页面或者差距域下加载后依旧存在,没有改动就不会暴发变化,并且可以储存格外长的name(2MB)

假若index页面请求远端服务器上的多寡,大家在该页面下创设iframe标签,该iframe的src指向服务器文件的地点(iframe标签src可以跨域),服务器文件里安装好window.name的值,然后再在index.html里面读取改iframe中的window.name的值。完美~

JavaScript

<body> <script type=”text/javascript”> iframe =
document.createElement(‘iframe’), iframe.src =
”; document.body.appendChild(iframe);
iframe.onload = function() { console.log(iframe.contentWindow.name) };
</script> </body>

1
2
3
4
5
6
7
8
9
10
<body>
  <script type="text/javascript">
    iframe = document.createElement(‘iframe’),
    iframe.src = ‘http://localhost:8080/data.php’;
    document.body.appendChild(iframe);
    iframe.onload = function() {
      console.log(iframe.contentWindow.name)
    };
  </script>
</body>

理所当然,那样依然不够的。

因为规定一经index.html页面和和该页面里的iframe框架的src如若不一样源,则也无能为力操作框架里的其余东西,所以就取不到iframe框架的name值了,告诉你大家不是一家的,你也绝不获得自身那边的数码。
既然要同源,那就换个src去指,前面说了无论怎么样加载window.name值都不会生成,于是大家在index.html相同目录下,新建了个proxy.html的空页面,修改代码如下:

 

JavaScript

<body> <script type=”text/javascript”> iframe =
document.createElement(‘iframe’), iframe.src =
”; document.body.appendChild(iframe);
iframe.onload = function() { iframe.src =
”;
console.log(iframe.contentWindow.name) }; </script> </body>

1
2
3
4
5
6
7
8
9
10
11
<body>
  <script type="text/javascript">
    iframe = document.createElement(‘iframe’),
    iframe.src = ‘http://localhost:8080/data.php’;
    document.body.appendChild(iframe);
    iframe.onload = function() {
      iframe.src = ‘http://localhost:81/cross-domain/proxy.html’;
      console.log(iframe.contentWindow.name)
    };
  </script>
</body>

好好就像很美好,在iframe载入进度中,连忙重置iframe.src的针对,使之与index.html同源,那么index页面就能去赢得它的name值了!不过现实是凶残的,iframe在切实可行中的表现是一贯不停地刷新,
也很好领会,每一趟触发onload时间后,重置src,相当于重新载入页面,又触发onload事件,于是就不停地刷新了(可是急需的数据仍是可以出口的)。修改后代码如下:

JavaScript

<body> <script type=”text/javascript”> iframe =
document.createElement(‘iframe’); iframe.style.display = ‘none’; var
state = 0; iframe.onload = function() { if(state === 1) { var data =
JSON.parse(iframe.contentWindow.name); console.log(data);
iframe.contentWindow.document.write(”); iframe.contentWindow.close();
document.body.removeChild(iframe); } else if(state === 0) { state = 1;
iframe.contentWindow.location =
”; } }; iframe.src =
”; document.body.appendChild(iframe);
</script> </body>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<body>
  <script type="text/javascript">
    iframe = document.createElement(‘iframe’);
    iframe.style.display = ‘none’;
    var state = 0;
    
    iframe.onload = function() {
      if(state === 1) {
          var data = JSON.parse(iframe.contentWindow.name);
          console.log(data);
          iframe.contentWindow.document.write(”);
          iframe.contentWindow.close();
        document.body.removeChild(iframe);
      } else if(state === 0) {
          state = 1;
          iframe.contentWindow.location = ‘http://localhost:81/cross-domain/proxy.html’;
      }
    };
 
    iframe.src = ‘http://localhost:8080/data.php’;
    document.body.appendChild(iframe);
  </script>
</body>

就此如上,大家就获得了服务器重临的多寡,但是有多少个标准化是必不可少的:

iframe标签的跨域能力
window.names属性值在文档刷新后依然留存的能力

location.hash + iframe 跨域

此跨域方法和地点介绍的可比相近,一样是动态插入一个iframe然后安装其src为服务端地址,而服务端同样输出一端js代码,也同时通过与子窗口之间的通讯来达成数据的传输。

有关锚点相信我们都早已精晓了,其实就是安装锚点,让文档指定的应和的义务。锚点的装置用a标签,然后href指向要跳转到的id,当然,前提是您得有个滚动条,不然也糟糕滚动嘛是吗。

而location.hash其实就是url的锚点。比如

基础知识补充落成,下边大家来说下何以兑现跨域

假如index页面要拿走远端服务器的数码,动态的插入一个iframe,将iframe的src执行服务器的地址,那时候的top
window
和包装那个iframe的子窗口是无法通讯的,因为同源策略,所以改变子窗口的路线就足以了,将数据作为改变后的路子的hash值加载路径上,然后就足以通讯了。将数据加在index页面地址的hash上,
index页面监听hash的更动,h5的hashchange方法

JavaScript

<body> <script type=”text/javascript”> function getData(url,
fn) { var iframe = document.createElement(‘iframe’);
iframe.style.display = ‘none’; iframe.src = url; iframe.onload =
function() { fn(iframe.contentWindow.location.hash.substring(1));
window.location.hash = ”; document.body.removeChild(iframe); };
document.body.appendChild(iframe); } // get data from server var url =
”; getData(url, function(data) { var
jsondata = JSON.parse(data); console.log(jsondata.name + ‘ ‘ +
jsondata.age); }); </script> </body>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<body>
  <script type="text/javascript">
    function getData(url, fn) {
      var iframe = document.createElement(‘iframe’);
      iframe.style.display = ‘none’;
      iframe.src = url;
 
      iframe.onload = function() {
        fn(iframe.contentWindow.location.hash.substring(1));
        window.location.hash = ”;
        document.body.removeChild(iframe);
      };
 
      document.body.appendChild(iframe);
    }
 
    // get data from server
    var url = ‘http://localhost:8080/data.php’;
    getData(url, function(data) {
      var jsondata = JSON.parse(data);
      console.log(jsondata.name + ‘ ‘ + jsondata.age);
    });
  </script>
</body>

补充表达:其实location.hash和window.name都是大抵的,都是使用全局对象属性的法子,然后那三种艺术和jsonp也是平等的,就是只能够够落实get请求

postMessage跨域

那是由H5提议来的一个炫酷的API,IE8+,chrome,ff都已经支持促成了这么些成效。那几个成效也是特其余简短,其中包蕴接受音信的Message时间,和发送音信的postMessage方法。

发送音讯的postMessage方法是向外围窗口发送音信

JavaScript

otherWindow.postMessage(message,targetOrigin);

1
otherWindow.postMessage(message,targetOrigin);

otherWindow指的是目的窗口,也就是要给哪一个window发送音信,是window.frames属性的积极分子要么是window.open方法创建的窗口。
Message是要发送的信息,类型为String,Object(IE8、9不帮助Obj),targetOrigin是限量新闻接受范围,不限定就用星号
*

收受音讯的message事件

JavaScript

var onmessage = function(event) { var data = event.data; var origin =
event.origin; } if(typeof window.addEventListener != ‘undefined’){
window.addEventListener(‘message’,onmessage,false); }else if(typeof
window.attachEvent != ‘undefined’){ window.attachEvent(‘onmessage’,
onmessage); }

1
2
3
4
5
6
7
8
9
10
var onmessage = function(event) {
  var data = event.data;
  var origin = event.origin;
}
 
if(typeof window.addEventListener != ‘undefined’){
    window.addEventListener(‘message’,onmessage,false);
}else if(typeof window.attachEvent != ‘undefined’){
    window.attachEvent(‘onmessage’, onmessage);
}

举个栗子

a.html()

JavaScript

<iframe id=”iframe” src=””
style=”display:none;”></iframe> <script> var iframe =
document.getElementById(‘iframe’); iframe.onload = function() { var data
= { name: ‘aym’ }; // 向neal传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data),
”); }; // 接受domain2重返数据
window.add伊夫ntListener(‘message’, function(e) { alert(‘data from neal
—> ‘ + e.data); }, false); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<iframe id="iframe" src="http://www.neal.cn/b.html" style="display:none;"></iframe>
<script>      
    var iframe = document.getElementById(‘iframe’);
    iframe.onload = function() {
        var data = {
            name: ‘aym’
        };
        // 向neal传送跨域数据
        iframe.contentWindow.postMessage(JSON.stringify(data), ‘http://www.neal.cn’);
    };
 
    // 接受domain2返回数据
    window.addEventListener(‘message’, function(e) {
        alert(‘data from neal —> ‘ + e.data);
    }, false);
</script>

b.html()

JavaScript

<script> // 接收domain1的多寡 window.add伊芙ntListener(‘message’,
function(e) { alert(‘data from nealyang —> ‘ + e.data); var data =
JSON.parse(e.data); if (data) { data.number = 16; //
处理后再发回nealyang window.parent.postMessage(JSON.stringify(data),
”); } }, false); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
    // 接收domain1的数据
    window.addEventListener(‘message’, function(e) {
        alert(‘data from nealyang —> ‘ + e.data);
 
        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;
 
            // 处理后再发回nealyang
            window.parent.postMessage(JSON.stringify(data), ‘http://www.nealyang.cn’);
        }
    }, false);
</script>

讲的相比较细:
跨域笔记
    有些东西不要太较真,因为没啥用

前端开发中,跨域使大家经常遭逢的一个题材,也是面试中时常被问到的有的标题,所以,这里,我们做个小结。小小意思,不足担心

Easiest: jQuery Plugin

最简便易行的,我怎么感觉越是复杂了…

略…

小结,因为要用第三方的服务器,所以既耗时又有不确定因素(比如服务器挂了),不合适用在真正项目中,自己玩玩尚可。

1 赞 收藏
评论

亚洲必赢官网 2

跨域资源共享 CORS

因为是当下主流的跨域解决方案。所以那边多介绍点。
简介

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource
sharing)。
它同意浏览器向跨源服务器,发出XMLHttpRequest请求,从而克制了AJAX只可以同源使用的限定。

CORS须求浏览器和服务器同时帮衬。近期,所有浏览器都支持该意义,IE浏览器不可以低于IE10。IE8+:IE8/9索要利用XDomainRequest对象来支撑CORS。

全套CORS通讯进度,都是浏览器自动已毕,不须求用户加入。对于开发者来说,CORS通讯与同源的AJAX通讯没有不一致,代码完全一致。浏览器一旦发觉AJAX请求跨源,就会活动抬高一些增大的头新闻,有时还会多出一遍附加的伸手,但用户不会有觉得。
由此,达成CORS通讯的关键是服务器。只要服务器已毕了CORS接口,就能够跨源通讯。
三种请求

说起来很搞笑,分为二种请求,一种是概括请求,另一种是非不难请求。只要知足下边条件就是大约请求

请求格局为HEAD、POST 或者 GET
http头信息不高于一下字段:Accept、Accept-Language 、 Content-Language、
Last-伊芙nt-ID、
Content-Type(限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain)

为什么要分成不难请求和非不难请求,因为浏览器对那三种请求情势的处理格局是见仁见智的。
不难易行请求
焦点流程

对此简易请求,浏览器直接发生CORS请求。具体来说,就是在头音信之中,增加一个Origin字段。
上边是一个事例,浏览器发现这一次跨源AJAX请求是简单请求,就自行在头新闻之中,添加一个Origin字段。

JavaScript

GET /cors HTTP/1.1 Origin: Host: api.alice.com
Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0

1
2
3
4
5
6
7
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0

Origin字段用来表明,本次请求来自哪个源(协议 + 域名 +
端口)。服务器根据那个值,决定是还是不是同意本次请求。

只要Origin指定的源,不在许可范围内,服务器会回去一个正常的HTTP回应。
浏览器发现,那个答复的头音讯尚未包涵Access-Control-Allow-Origin字段(详见下文),就精通出错了,从而抛出一个谬误,被XMLHttpRequest的onerror回调函数捕获。

注意,那种错误无法透过情景码识别,因为HTTP回应的状态码有可能是200。

比方Origin指定的域名在获准范围内,服务器再次来到的响应,会多出多少个头音讯字段。

JavaScript

Access-Control-Allow-Origin:
Access-Control-Allow-Credentials: true Access-Control-Expose-Headers:
FooBar Content-Type: text/html; charset=utf-8

1
2
3
4
   Access-Control-Allow-Origin: http://api.bob.com
   Access-Control-Allow-Credentials: true
   Access-Control-Expose-Headers: FooBar
   Content-Type: text/html; charset=utf-8

上边的头音信之中,有三个与CORS请求相关的字段,都以Access-Control-起先

  • Access-Control-Allow-Origin
    :该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的央求
  • Access-Control-Allow-Credentials:
    该字段可选。它的值是一个布尔值,表示是还是不是允许发送Cookie。默许意况下,Cookie不包涵在CORS请求之中。设为true,即表示服务器明确批准,Cookie可以分包在伸手中,一起发给服务器。那一个值也只能设为true,假设服务器不要浏览器发送Cookie,删除该字段即可。
  • Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只可以获得6个宗旨字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如若想得到其它字段,就务须在Access-Control-Expose-Headers里面指定。

withCredentials 属性

下边说到,CORS请求默许不发送Cookie和HTTP认证新闻。假如要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。

单向,开发者必须在AJAX请求中开拓withCredentials属性。

JavaScript

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest包容 //
前端安装是还是不是带cookie xhr.withCredentials = true; xhr.open(‘post’,
”, true);
xhr.setRequestHeader(‘Content-Type’,
‘application/x-www-form-urlencoded’); xhr.send(‘user=admin’);
xhr.onreadystatechange = function() { if (xhr.readyState == 4 &&
xhr.status == 200) { alert(xhr.responseText); } }; // jquery $.ajax({
… xhrFields: { withCredentials: true // 前端安装是还是不是带cookie },
crossDomain: true, // 会让请求头中带有跨域的附加音讯,但不会含cookie …
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
 
// 前端设置是否带cookie
xhr.withCredentials = true;
 
xhr.open(‘post’, ‘http://www.domain2.com:8080/login’, true);
xhr.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
xhr.send(‘user=admin’);
 
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};
 
// jquery
$.ajax({
    …
   xhrFields: {
       withCredentials: true    // 前端设置是否带cookie
   },
   crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie
    …
});

不然,即使服务器同意发送库克ie,浏览器也不会发送。或者,服务器须求安装Cookie,浏览器也不会处理。
可是,如果省略withCredentials设置,有的浏览器依旧会同步发送Cookie。这时,能够显式关闭withCredentials。

亟待专注的是,如若要发送Cookie,Access-Control-Allow-Origin就不可以设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie照旧根据同源政策,唯有用服务器域名设置的库克ie才会上传,其他域名的库克ie并不会上传,且(跨源)原网页代码中的document.cookie也不可能读取服务器域名下的Cookie。
非简单请求

非简单请求是那种对服务器有特殊需要的伏乞,比如请求方法是PUT或DELETE,或者Content-Type字段的品类是application/json。

非简单请求的CORS请求,会在专业通讯以前,增添一回HTTP查询请求,称为”预检”请求(preflight)。

浏览器先通晓服务器,当前网页所在的域名是或不是在服务器的认可名单之中,以及可以应用什么HTTP动词和头音信字段。只有得到肯定答复,浏览器才会暴发正式的XMLHttpRequest请求,否则就报错。

JavaScript

var url = ”; var xhr = new XMLHttpRequest();
xhr.open(‘PUT’, url, true); xhr.setRequestHeader(‘X-Custom-Header’,
‘value’); xhr.send();

1
2
3
4
5
var url = ‘http://api.alice.com/cors’;
var xhr = new XMLHttpRequest();
xhr.open(‘PUT’, url, true);
xhr.setRequestHeader(‘X-Custom-Header’, ‘value’);
xhr.send();

浏览器发现,那是一个非简单请求,就自动发出一个”预检”请求,须求服务器确认可以这样请求。下边是那几个”预检”请求的HTTP头音讯。

JavaScript

OPTIONS /cors HTTP/1.1 Origin:
Access-Control-Request-Method: PUT Access-Control-Request-Headers:
X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection:
keep-alive User-Agent: Mozilla/5.0…

1
2
3
4
5
6
7
8
    OPTIONS /cors HTTP/1.1
   Origin: http://api.bob.com
   Access-Control-Request-Method: PUT
   Access-Control-Request-Headers: X-Custom-Header
   Host: api.alice.com
   Accept-Language: en-US
   Connection: keep-alive
   User-Agent: Mozilla/5.0…

“预检”请求用的央求方法是OPTIONS,表示这几个请求是用来了解的。头音信里面,关键字段是Origin,表示请求来自哪个源。

除开Origin字段,”预检”请求的头音讯包含五个奇特字段。

Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到什么样HTTP方法,上例是PUT。
Access-Control-Request-Headers:该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头新闻字段,上例是X-Custom-Header

预检请求的作答

服务器收到”预检”请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段未来,确认允许跨源请求,就可以做出回应

JavaScript

HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server:
Apache/2.0.61 (Unix) Access-Control-Allow-Origin:
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html;
charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive:
timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

地点的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示

如果浏览器否定了”预检”请求,会回去一个好端端的HTTP回应,不过并未其余CORS相关的头消息字段。这时,浏览器就会肯定,服务器不一样意预检请求,因而触发一个谬误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错音信。

服务器回应的其余CORS相关字段如下:

JavaScript

Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true Access-Control-Max-Age: 1728000

1
2
3
4
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
  • Access-Control-Allow-Methods:该字段必需,它的值是逗号分隔的一个字符串,声明服务器帮忙的持有跨域请求的主意。注意,重回的是独具协助的法门,而不单是浏览器请求的不胜格局。那是为了避免频仍”预检”请求。
  • Access-Control-Allow-Headers:假使浏览器请求包罗Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是少不了的。它也是一个逗号分隔的字符串,注明服务器扶助的享有头消息字段,不压制浏览器在”预检”中呼吁的字段。
  • Access-Control-Allow-Credentials: 该字段与简便请求时的含义相同。
  • Access-Control-马克斯-Age:
    该字段可选,用来指定这一次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此时期,不用发出另一条预检请求。

浏览器正常请求应对

即使服务器通过了”预检”请求,未来每一遍浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头音讯字段。服务器的答应,也都会有一个Access-Control-Allow-Origin头信息字段。

JavaScript

PUT /cors HTTP/1.1 Origin: Host: api.alice.com
X-Custom-Header: value Accept-Language: en-US Connection: keep-alive
User-Agent: Mozilla/5.0…

1
2
3
4
5
6
7
PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0…

浏览器的常规CORS请求。上面头信息的Origin字段是浏览器自动抬高的。上面是服务器常规的答疑。

JavaScript

Access-Control-Allow-Origin: Content-Type: text/html;
charset=utf-8

1
2
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8

Access-Control-Allow-Origin字段是历次回应都一定包括的
结束语

CORS与JSONP的选择目的相同,不过比JSONP更强大。JSONP只协理GET请求,CORS扶助所有类型的HTTP请求。JSONP的优势在于协理老式浏览器,以及可以向不支持CORS的网站呼吁数据。
WebSocket磋商跨域

WebSocket
protocol是HTML5一种新的情商。它完成了浏览器与服务器全双工通讯,同时同意跨域通信,是server
push技术的一种很好的贯彻。

原生WebSocket
API使用起来不太便宜,大家利用Socket.io,它很好地卷入了webSocket接口,提供了更简便、灵活的接口,也对不帮衬webSocket的浏览器提供了向下包容。

前端代码:

JavaScript

<div>user input:<input type=”text”></div> <script
src=”./socket.io.js”></script> <script> var socket =
io(”); // 连接成功拍卖 socket.on(‘connect’,
function() { // 监听服务端音信 socket.on(‘message’, function(msg) {
console.log(‘data from server: —> ‘ + msg); }); // 监听服务端关闭
socket.on(‘disconnect’, function() { console.log(‘Server socket has
closed.’); }); }); document.getElementsByTagName(‘input’)[0].onblur =
function() { socket.send(this.value); }; </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div>user input:<input type="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io(‘http://www.domain2.com:8080’);
 
// 连接成功处理
socket.on(‘connect’, function() {
    // 监听服务端消息
    socket.on(‘message’, function(msg) {
        console.log(‘data from server: —> ‘ + msg);
    });
 
    // 监听服务端关闭
    socket.on(‘disconnect’, function() {
        console.log(‘Server socket has closed.’);
    });
});
 
document.getElementsByTagName(‘input’)[0].onblur = function() {
    socket.send(this.value);
};
</script>

node Server

JavaScript

var http = require(‘http’); var socket = require(‘socket.io’); //
启http服务 var server = http.createServer(function(req, res) {
res.writeHead(200, { ‘Content-type’: ‘text/html’ }); res.end(); });
server.listen(‘8080’); console.log(‘Server is running at port 8080…’);
// 监听socket连接 socket.listen(server).on(‘connection’,
function(client) { // 接收音信 client.on(‘message’, function(msg) {
client.send(‘hello:’ + msg); console.log(‘data from client: —> ‘ +
msg); }); // 断开处理 client.on(‘disconnect’, function() {
console.log(‘Client socket has closed.’); }); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var http = require(‘http’);
var socket = require(‘socket.io’);
 
// 启http服务
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        ‘Content-type’: ‘text/html’
    });
    res.end();
});
 
server.listen(‘8080’);
console.log(‘Server is running at port 8080…’);
 
// 监听socket连接
socket.listen(server).on(‘connection’, function(client) {
    // 接收信息
    client.on(‘message’, function(msg) {
        client.send(‘hello:’ + msg);
        console.log(‘data from client: —> ‘ + msg);
    });
 
    // 断开处理
    client.on(‘disconnect’, function() {
        console.log(‘Client socket has closed.’);
    });
});

node代理跨域

node中间件落成跨域代理,是经过启一个代理服务器,完结多少的转折,也足以透过安装cookieDomainRewrite参数修改响应头中cookie中域名,完毕当前域的cookie写入,方便接口登录认证。

利用node + express + http-proxy-middleware搭建一个proxy服务器

前端代码

JavaScript

var xhr = new XMLHttpRequest(); // 前端开关:浏览器是或不是读写cookie
xhr.withCredentials = true; // 访问http-proxy-middleware代理服务器
xhr.open(‘get’, ”, true);
xhr.send();

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
 
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
 
// 访问http-proxy-middleware代理服务器
xhr.open(‘get’, ‘http://www.domain1.com:3000/login?user=admin’, true);
xhr.send();

后端代码

JavaScript

var express = require(‘express’); var proxy =
require(‘http-proxy-middleware’); var app = express(); app.use(‘/’,
proxy({ // 代理跨域目的接口 target: ”,
changeOrigin: true, // 修改响应头音信,完成跨域并允许带cookie
onProxyRes: function(proxyRes, req, res) {
res.header(‘Access-Control-Allow-Origin’, ”);
res.header(‘Access-Control-Allow-Credentials’, ‘true’); }, //
修改响应信息中的cookie域名 cookieDomainRewrite: ‘www.domain1.com’ //
可以为false,表示不修改 })); app.listen(3000); console.log(‘Proxy server
is listen at port 3000…’);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var express = require(‘express’);
var proxy = require(‘http-proxy-middleware’);
var app = express();
 
app.use(‘/’, proxy({
    // 代理跨域目标接口
    target: ‘http://www.domain2.com:8080’,
    changeOrigin: true,
 
    // 修改响应头信息,实现跨域并允许带cookie
    onProxyRes: function(proxyRes, req, res) {
        res.header(‘Access-Control-Allow-Origin’, ‘http://www.domain1.com’);
        res.header(‘Access-Control-Allow-Credentials’, ‘true’);
    },
 
    // 修改响应信息中的cookie域名
    cookieDomainRewrite: ‘www.domain1.com’  // 可以为false,表示不修改
}));
 
app.listen(3000);
console.log(‘Proxy server is listen at port 3000…’);

nginx代理跨域

NGINX其实个人尚未怎么玩过,所以暂且也就无法误人子弟了,原谅作者才疏尚浅~
有机会学习切磋再回去补充~~
交流

迎接参与react技术栈、前端技术杂谈QQ群

前端技术随想:604953717
react技术栈:398240621

参考文档

1 赞 6 收藏
评论

亚洲必赢官网 3

    jsonp和cors知道就好,其余的刺探一下就好
  同源:是指同域名(主域名与二级域名,即子域名),同协议,同端口。是浏览器的一种最基本最中央的安全策略。

 

  
 1.”同源策略”,即同域名(domain或ip)、同端口、同协议的才干相互获取资源,而不可能访问其他域的资源。

何以是跨域

 

跨域,是指浏览器不可能进行其它网站的台本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安康限制。

同源策略限制了一晃行为:

  • Cookie、LocalStorage 和 IndexDB 不能够读取

  • DOM 和 JS 对象不能得到

  • Ajax请求发送不出来

亚洲必赢官网 4
  
 2.jsonp跨域格局,就是利用script的src来变相发送get请求,在链接里会发送一个函数名,而json数据作为
函数的参数被回调函数传递过来再分析拔取。

 

//据商量:<script>、<a>、<img>、<iframe>等标签可以完成跨域,因为有src(a的href),能够拿走外域的信息,src属性不受同源策略的范围,可以取得其余服务器上的台本并推行。
    3.jsonp用jq达成,有多个主意:$.getJSON 和 $.ajax
//callback前面的?会由jquery自动生成方法名
$.getJSON(‘
    console.log(data.msg);
});
还有一种更常用的是:$.ajax,只要制定datatype为jsonp即可:
$.ajax({
    url:

    dataType:‘jsonp’,
    jsonpCallback:‘demo’,//可省略
    success:function(data){
     
console.log(data.msg);//msg是json数据中的一个name。未来可以是其它此外
    }
});
    
    4.jsonp缺点:
    ·没有有关调用错误的处理函数,败北会以浏览器默许方式处理
    ·只协助get请求。由此安全性不高
    5.json亮点:协助老浏览器包容,ie8以下也可以。
    6.CORS格局,针对高档浏览器。
透过修改document.domain为根基域名的章程来举行通讯,但要注意协议和端口也必须一律、
  
 7.各样iframe都有包装他的window对象,而以此window是最外层窗口的子对象,所以,window.name属性就可以被共享。
  
 8.CORS:跨域资源共享,w3c标准,协理包容ie8,(IE8和IE9须求利用XDomainRequest对象来支撑CORS)。主流的跨域解决方案
  
 9.CORS的核感情想是经过一多元新增的HTTP头新闻来落成服务器和客户端之间的通讯。【所以,须求服务端做好对应安插来合营前端】
    10.Origin尾部:包含请求页面的源音讯(协议、域名和端口)。功能是让服务器按照这么些尾部音讯来支配是还是不是授予响应。
  
 11.Access-Control-Allow-Origin:请求可以接受时:服务器就会回来新闻,在其尾部中:发一样的呼应的源新闻(即使是公共资源,就发*。大部分状态,我们都爱好一向写成*返回,*意味着任意外域资源都可以访问,但那样安全性不高。)
    12.只要没有尾部,或底部音讯源不般配,就会重临错误驳回请求。
    13.请求和响应都不分包cookie音讯

 

科普的跨域场景

 

所谓的同源是指,域名、协议、端口均为同一。

调用
非跨域

 

调用
跨域,主域不同

 

调用
跨域,子域名不相同

 

调用
跨域,端口不相同

 

调用
跨域,协议不一致

 

localhost 调用 127.0.0.1 跨域

 

跨域的解决办法

jsonp跨域

jsonp跨域其实也是JavaScript设计方式中的一种代理方式。在html页面中通过相应的竹签从分化域名下加载静态资源文件是被浏览器允许的,所以咱们得以经过那一个“犯罪漏洞”来展开跨域。一般,大家可以动态的开创script标签,再去伏乞一个带参网址来完结跨域通讯

//原生的完毕方式

let script = document.createElement(‘script’);

 

script.src = ”;

 

document.body.appendChild(script);

 

function callback(res) {

  console.log(res);

}

自然,jquery也接济jsonp的贯彻形式

$.ajax({

    url:”,

    type:’GET’,

    dataType:’jsonp’,//请求格局为jsonp

    jsonpCallback:’callback’,

    data:{

        “username”:”Nealyang”

    }

})

固然如此那种措施万分好用,可是一个最大的短处是,只好够已毕get请求

document.domain + iframe 跨域

那种跨域的办法最关键的是须要主域名相同。什么是主域名相同呢?
www.nealyang.cn aaa.nealyang.cn ba.ad.nealyang.cn
那八个主域名都是nealyang.cn,而主域名差距的就无法用此措施。

假如如今a.nealyang.cn 和 b.nealyang.cn 分别对应指向差别ip的服务器。

a.nealyang.cn 下有一个test.html文件

<!DOCTYPE html>

<html lang=”en”>

<head>

    <meta charset=”UTF-8″>

    <title>html</title>

    <script type=”text/javascript” src =
“jquery-1.12.1.js”></script>

</head>

<body>

    <div>A页面</div>

    <iframe

    style = “display : none”

    name = “iframe1”

    id = “iframe”

    src=””
frameborder=”0″></iframe>

    <script type=”text/javascript”>

        $(function(){

            try{

                document.domain = “nealyang.cn”

            }catch(e){}

            $(“#iframe”).load(function(){

                var jq = document.getElementById(‘iframe’).contentWindow.$

                jq.get(“

                    console.log(data);

                });

            })

        })

    </script>

</body>

</html>

运用 iframe 加载 其余域下的文件(nealyang.cn/1.html), 同时
document.domain 设置成 nealyang.cn ,当 iframe 加载完成后就可以拿走
nealyang.cn 域下的大局对象, 此时尝试着去伏乞 nealyang.cn 域名下的
test.json (此时得以请求接口),就会发现数目请求战败了~~
惊不惊喜,意不奇怪!!!!!!!

数量请求失败,目标绝非达到,自然是还少一步:

<!DOCTYPE html>

<html lang=”en”>

<head>

    <meta charset=”UTF-8″>

    <title>html</title>

    <script type=”text/javascript” src =
“jquery-1.12.1.js”></script>

    <script type=”text/javascript”>

        $(function(){

            try{

                document.domain = “nealyang.com”

            }catch(e){}

        })

    </script>

</head>

<body>

    <div id = “div1”>B页面</div>

</body>

</html>

那时候在展开刷新浏览器,就会意识数目本次的确是打响了

window.name + iframe 跨域

window.name属性可设置或者重回存放窗口名称的一个字符串。他的神器之处在于name值在差距页面或者分裂域下加载后如故存在,没有改动就不会发生变化,并且可以储存相当长的name(2MB)

若是index页面请求远端服务器上的数量,大家在该页面下创设iframe标签,该iframe的src指向服务器文件的地方(iframe标签src可以跨域),服务器文件里安装好window.name的值,然后再在index.html里面读取改iframe中的window.name的值。完美~

<body>

  <script type=”text/javascript”>

    iframe = document.createElement(‘iframe’),

    iframe.src = ”;

    document.body.appendChild(iframe);

    iframe.onload = function() {

      console.log(iframe.contentWindow.name)

    };

  </script>

</body>

本来,那样依旧不够的。

因为规定一经index.html页面和和该页面里的iframe框架的src如若不一致源,则也无从操作框架里的别样东西,所以就取不到iframe框架的name值了,告诉您大家不是一家的,你也毫不得到本人那边的数据。
既然要同源,那就换个src去指,前边说了无论怎么样加载window.name值都不会转移,于是大家在index.html相同目录下,新建了个proxy.html的空页面,修改代码如下:

<body>

  <script type=”text/javascript”>

    iframe = document.createElement(‘iframe’),

    iframe.src = ”;

    document.body.appendChild(iframe);

    iframe.onload = function() {

      iframe.src = ”;

      console.log(iframe.contentWindow.name)

    };

  </script>

</body>

良好如同很美好,在iframe载入进度中,连忙重置iframe.src的对准,使之与index.html同源,那么index页面就能去赢得它的name值了!可是具体是暴虐的,iframe在实际中的表现是直接不停地刷新,
也很好通晓,每趟触发onload时间后,重置src,相当于重新载入页面,又触发onload事件,于是就不停地刷新了(但是急需的数量仍可以出口的)。修改后代码如下:

<body>

  <script type=”text/javascript”>

    iframe = document.createElement(‘iframe’);

    iframe.style.display = ‘none’;

    var state = 0;

 

    iframe.onload = function() {

      if(state === 1) {

          var data = JSON.parse(iframe.contentWindow.name);

          console.log(data);

          iframe.contentWindow.document.write(”);

          iframe.contentWindow.close();

        document.body.removeChild(iframe);

      } else if(state === 0) {

          state = 1;

          iframe.contentWindow.location = ”;

      }

    };

 

    iframe.src = ”;

    document.body.appendChild(iframe);

  </script>

</body>

据此如上,我们就得到了服务器再次回到的数据,不过有多少个规格是需要的:

  • iframe标签的跨域能力

  • window.names属性值在文档刷新后依然存在的力量

location.hash + iframe 跨域

此跨域方法和地方介绍的可比相近,一样是动态插入一个iframe然后安装其src为服务端地址,而服务端同样输出一端js代码,也还要通过与子窗口之间的通讯来成功数据的传输。

关于锚点相信大家都早已知道了,其实就是设置锚点,让文档指定的照应的职位。锚点的安装用a标签,然后href指向要跳转到的id,当然,前提是你得有个滚动条,不然也不佳滚动嘛是啊。

而location.hash其实就是url的锚点。比如

基础知识补充完结,下边我们来说下怎么贯彻跨域

设若index页面要获取远端服务器的数量,动态的插入一个iframe,将iframe的src执行服务器的地址,那时候的top
window
和打包这几个iframe的子窗口是无法通讯的,因为同源策略,所以改变子窗口的门道就可以了,将数据作为改变后的路线的hash值加载路径上,然后就能够通讯了。将数据加在index页面地址的hash上,
index页面监听hash的更动,h5的hashchange方法

<body>

  <script type=”text/javascript”>

    function getData(url, fn) {

      var iframe = document.createElement(‘iframe’);

      iframe.style.display = ‘none’;

      iframe.src = url;

 

      iframe.onload = function() {

        fn(iframe.contentWindow.location.hash.substring(1));

        window.location.hash = ”;

        document.body.removeChild(iframe);

      };

 

      document.body.appendChild(iframe);

    }

 

    // get data from server

    var url = ”;

    getData(url, function(data) {

      var jsondata = JSON.parse(data);

      console.log(jsondata.name + ‘ ‘ + jsondata.age);

    });

  </script>

</body>

填补表明:其实location.hash和window.name都是基本上的,都是应用全局对象属性的主意,然后那三种方法和jsonp也是一律的,就是只好够落到实处get请求

postMessage跨域

那是由H5提议来的一个炫酷的API,IE8+,chrome,ff都早就支撑促成了那么些效果。这些效果也是特其余简易,其中囊括接受音信的Message时间,和发送音信的postMessage方法。

发送音讯的postMessage方法是向外围窗口发送音信

otherWindow.postMessage(message,targetOrigin);

otherWindow指的是目标窗口,也就是要给哪一个window发送音讯,是window.frames属性的积极分子要么是window.open方法创立的窗口。
Message是要发送的音讯,类型为String,Object(IE8、9不帮忙Obj),targetOrigin是限量新闻接受范围,不限制就用星号
*

接受音讯的message事件

var onmessage = function(event) {

  var data = event.data;

  var origin = event.origin;

}

 

if(typeof window.addEventListener != ‘undefined’){

    window.addEventListener(‘message’,onmessage,false);

}else if(typeof window.attachEvent != ‘undefined’){

    window.attachEvent(‘onmessage’, onmessage);

}

举个栗子

a.html()

<iframe id=”iframe” src=”” style=”display:none;”></iframe>

<script>

    var iframe = document.getElementById(‘iframe’);

    iframe.onload = function() {

        var data = {

            name: ‘aym’

        };

        // 向neal传送跨域数据

        iframe.contentWindow.postMessage(JSON.stringify(data), ”);

    };

 

    // 接受domain2重回数据

    window.addEventListener(‘message’, function(e) {

        alert(‘data from neal —> ‘ + e.data);

    }, false);

</script>

b.html()

<script>

    // 接收domain1的数据

    window.addEventListener(‘message’, function(e) {

        alert(‘data from nealyang —> ‘ + e.data);

 

        var data = JSON.parse(e.data);

        if (data) {

            data.number = 16;

 

            // 处理后再发回nealyang

            window.parent.postMessage(JSON.stringify(data), ”);

        }

    }, false);

</script>

跨域资源共享 CORS

因为是时下主流的跨域解决方案。所以那里多介绍点。

简介

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource
sharing)。
它同意浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只好同源使用的界定。

CORS须求浏览器和服务器同时帮忙。方今,所有浏览器都援救该功用,IE浏览器不可能低于IE10。IE8+:IE8/9亟需拔取XDomainRequest对象来支撑CORS。

全总CORS通讯进程,都是浏览器自动已毕,不需求用户出席。对于开发者来说,CORS通讯与同源的AJAX通讯没有分化,代码完全一致。浏览器一旦发现AJAX请求跨源,就会自行抬高一些外加的头消息,有时还会多出三遍附加的请求,但用户不会有痛感。
因而,落成CORS通讯的首借使服务器。只要服务器落成了CORS接口,就足以跨源通讯。

三种请求

说起来很搞笑,分为三种请求,一种是粗略请求,另一种是非不难请求。只要知足下边条件就是简简单单请求

  • 恳请形式为HEAD、POST 或者 GET

  • http头音讯不超出一下字段:Accept、Accept-Language 、
    Content-Language、 Last-伊芙nt-ID、
    Content-Type(限于八个值:application/x-www-form-urlencoded、multipart/form-data、text/plain)

怎么要分成不难请求和非简单请求,因为浏览器对那两种请求格局的处理格局是不相同的。

简单的说请求

主导流程

对此简易请求,浏览器直接发生CORS请求。具体来说,就是在头新闻之中,增加一个Origin字段。
下边是一个例子,浏览器发现这一次跨源AJAX请求是简单请求,就自行在头音信之中,添加一个Origin字段。

GET /cors HTTP/1.1

Origin: 

Host: api.alice.com

Accept-Language: en-US

Connection: keep-alive

User-Agent: Mozilla/5.0

Origin字段用来表明,这一次请求来自哪个源(协议 + 域名 +
端口)。服务器按照那几个值,决定是或不是允许这一次请求。

只要Origin指定的源,不在许可范围内,服务器会再次来到一个正常的HTTP回应。
浏览器发现,那些答复的头音讯并未包括Access-Control-Allow-Origin字段(详见下文),就知晓出错了,从而抛出一个荒谬,被XMLHttpRequest的onerror回调函数捕获。

小心,那种指鹿为马不可能通过情状码识别,因为HTTP回应的状态码有可能是200。

一旦Origin指定的域名在许可范围内,服务器再次回到的响应,会多出多少个头音讯字段。

Access-Control-Allow-Origin: 

   Access-Control-Allow-Credentials: true

   Access-Control-Expose-Headers: FooBar

   Content-Type: text/html; charset=utf-8

上边的头音信之中,有四个与CORS请求相关的字段,都以Access-Control-起始

  • Access-Control-Allow-Origin
    :该字段是必须的。它的值要么是呼吁时Origin字段的值,要么是一个*,表示接受任意域名的请求

  • Access-Control-Allow-Credentials:
    该字段可选。它的值是一个布尔值,表示是还是不是允许发送Cookie。默许景况下,Cookie不包蕴在CORS请求之中。设为true,即表示服务器明确准予,库克ie可以包罗在乞请中,一起发给服务器。那些值也不得不设为true,若是服务器不要浏览器发送Cookie,删除该字段即可。

  • Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只好拿到6个主导字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。借使想获得其他字段,就亟须在Access-Control-Expose-Headers里面指定。

 
withCredentials 属性

上面说到,CORS请求默认不发送Cookie和HTTP认证信息。即使要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。

另一方面,开发者必须在AJAX请求中开辟withCredentials属性。

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容

 

// 前端安装是还是不是带cookie

xhr.withCredentials = true;

 

xhr.open(‘post’, ”, true);

xhr.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);

xhr.send(‘user=admin’);

 

xhr.onreadystatechange = function() {

    if (xhr.readyState == 4 && xhr.status == 200) {

        alert(xhr.responseText);

    }

};

 

// jquery

$.ajax({

    …

   xhrFields: {

       withCredentials: true // 前端安装是还是不是带cookie

   },

   crossDomain: true, //
会让请求头中含有跨域的额外音信,但不会含cookie

    …

});

否则,尽管服务器同意发送Cookie,浏览器也不会发送。或者,服务器需要安装Cookie,浏览器也不会处理。
不过,即便省略withCredentials设置,有的浏览器依旧会共同发送Cookie。那时,可以显式关闭withCredentials。

亟需注意的是,若是要发送Cookie,Access-Control-Allow-Origin就无法设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依旧根据同源政策,唯有用劳动器域名设置的Cookie才会上传,其余域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无能为力读取服务器域名下的库克ie。

非简单请求

非不难请求是那种对服务器有特殊须求的伸手,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

非简单请求的CORS请求,会在标准通讯往日,增添五次HTTP查询请求,称为”预检”请求(preflight)。

浏览器先精通服务器,当前网页所在的域名是或不是在服务器的准许名单之中,以及可以利用什么HTTP动词和头消息字段。只有得到一定回应,浏览器才会时有发生正式的XMLHttpRequest请求,否则就报错。

var url = ”;

var xhr = new XMLHttpRequest();

xhr.open(‘PUT’, url, true);

xhr.setRequestHeader(‘X-Custom-Header’, ‘value’);

xhr.send();

浏览器发现,那是一个非简单请求,就活动发出一个”预检”请求,要求服务器确认同以那样请求。下边是其一”预检”请求的HTTP头新闻。

OPTIONS /cors HTTP/1.1

   Origin: 

   Access-Control-Request-Method: PUT

   Access-Control-Request-Headers: X-Custom-Header

   Host: api.alice.com

   Accept-Language: en-US

   Connection: keep-alive

   User-Agent: Mozilla/5.0…

“预检”请求用的乞求方法是OPTIONS,表示这么些请求是用来询问的。头音信里面,关键字段是Origin,表示请求来自哪个源。

除外Origin字段,”预检”请求的头音讯包蕴五个尤其字段。

  • Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到何以HTTP方法,上例是PUT。

  • Access-Control-Request-Headers:该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头音信字段,上例是X-Custom-Header

 
预检请求的答问

服务器收到”预检”请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段将来,确认允许跨源请求,就可以做出回复

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 01:15:39 GMT

Server: Apache/2.0.61 (Unix)

Access-Control-Allow-Origin: 

Access-Control-Allow-Methods: GET, POST, PUT

Access-Control-Allow-Headers: X-Custom-Header

Content-Type: text/html; charset=utf-8

Content-Encoding: gzip

Content-Length: 0

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Content-Type: text/plain

地点的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示

一旦浏览器否定了”预检”请求,会回来一个正规的HTTP回应,但是尚未其余CORS相关的头新闻字段。那时,浏览器就会确认,服务器不容许预检请求,因而触发一个荒唐,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错音讯。

服务器回应的此外CORS相关字段如下:

Access-Control-Allow-Methods: GET, POST, PUT

Access-Control-Allow-Headers: X-Custom-Header

Access-Control-Allow-Credentials: true

Access-Control-Max-Age: 1728000

亚洲必赢官网 , 

  • Access-Control-Allow-Methods:该字段必需,它的值是逗号分隔的一个字符串,注解服务器帮衬的持有跨域请求的不二法门。注意,再次来到的是独具帮助的情势,而不单是浏览器请求的不行形式。那是为着防止频仍”预检”请求。

  • Access-Control-Allow-Headers:假使浏览器请求包蕴Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是不可或缺的。它也是一个逗号分隔的字符串,注解服务器协助的富有头音信字段,不幸免浏览器在”预检”中呼吁的字段。

  • Access-Control-Allow-Credentials: 该字段与简短请求时的意思相同。

  • Access-Control-马克斯-Age:
    该字段可选,用来指定本次预检请求的有效期,单位为秒。上边结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此时期,不用发出另一条预检请求。

 
浏览器正常请求应对

若是服务器通过了”预检”请求,未来每一回浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头音讯字段。服务器的应对,也都会有一个Access-Control-Allow-Origin头新闻字段。

PUT /cors HTTP/1.1

Origin: 

Host: api.alice.com

X-Custom-Header: value

Accept-Language: en-US

Connection: keep-alive

User-Agent: Mozilla/5.0…

浏览器的健康CORS请求。上面头新闻的Origin字段是浏览器自动抬高的。下边是服务器常规的对答。

Access-Control-Allow-Origin: 

Content-Type: text/html; charset=utf-8

Access-Control-Allow-Origin字段是每便回应都必然包括的

结束语

CORS与JSONP的施用目标相同,不过比JSONP更强有力。JSONP只帮忙GET请求,CORS支持所有类其他HTTP请求。JSONP的优势在于援救老式浏览器,以及可以向不扶助CORS的网站呼吁数据。

WebSocket切磋跨域

WebSocket
protocol是HTML5一种新的合计。它完成了浏览器与服务器全双工通讯,同时允许跨域通信,是server
push技术的一种很好的兑现。

原生WebSocket
API使用起来不太有利,我们运用Socket.io,它很好地包裹了webSocket接口,提供了更简便易行、灵活的接口,也对不支持webSocket的浏览器提供了向下包容。

前者代码:

<div>user input:<input type=”text”></div>

<script src=”./socket.io.js”></script>

<script>

var socket = io(”);

 

// 连接成功拍卖

socket.on(‘connect’, function() {

    // 监听服务端音信

    socket.on(‘message’, function(msg) {

        console.log(‘data from server: —> ‘ + msg);

    });

 

    // 监听服务端关闭

    socket.on(‘disconnect’, function() {

        console.log(‘Server socket has closed.’);

    });

});

 

document.getElementsByTagName(‘input’)[0].onblur = function() {

    socket.send(this.value);

};

</script>

node Server

var http = require(‘http’);

var socket = require(‘socket.io’);

 

// 启http服务

var server = http.createServer(function(req, res) {

    res.writeHead(200, {

        ‘Content-type’: ‘text/html’

    });

    res.end();

});

 

server.listen(‘8080’);

console.log(‘Server is running at port 8080…’);

 

// 监听socket连接

socket.listen(server).on(‘connection’, function(client) {

    // 接收消息

    client.on(‘message’, function(msg) {

        client.send(‘hello:’ + msg);

        console.log(‘data from client: —> ‘ + msg);

    });

 

    // 断开处理

    client.on(‘disconnect’, function() {

        console.log(‘Client socket has closed.’);

    });

});

node代理跨域

node中间件完成跨域代理,是通过启一个代理服务器,完结数据的转折,也足以经过安装cookieDomainRewrite参数修改响应头中cookie中域名,完结当前域的cookie写入,方便接口登录认证。

接纳node + express + http-proxy-middleware搭建一个proxy服务器

前者代码

var xhr = new XMLHttpRequest();

 

// 前端开关:浏览器是还是不是读写cookie

xhr.withCredentials = true;

 

// 访问http-proxy-middleware代理服务器

xhr.open(‘get’, ”, true);

xhr.send();

后端代码

var express = require(‘express’);

var proxy = require(‘http-proxy-middleware’);

var app = express();

 

app.use(‘/’, proxy({

    // 代理跨域目的接口

    target: ”,

    changeOrigin: true,

 

    // 修改响应头信息,完成跨域并同意带cookie

    onProxyRes: function(proxyRes, req, res) {

        res.header(‘Access-Control-Allow-Origin’, ”);

        res.header(‘Access-Control-Allow-Credentials’, ‘true’);

    },

 

    // 修改响应音讯中的cookie域名

    cookieDomainRewrite: ‘www.domain1.com’ // 可以为false,表示不改动

}));

 

app.listen(3000);

console.log(‘Proxy server is listen at port 3000…’);

nginx代理跨域

NGINX其实个人尚未怎么玩过,所以暂且也就无法误人子弟了,原谅作者才疏尚浅~
有机遇学习商讨再回到补充~~

参照文档

 

网站地图xml地图