跨域

跨域的兴起主要是为了解决解决安全性的问题,浏览器采用同源策略的方法,对js进行限制,防止了恶意用户获取非法数据,同时也防止了大部分的XSS共计(用户向网站注入js脚本)。

浏览器两种同源策略出现跨域问题

  • DOM同源策略:禁止对不同源的Dom进行操作,主要包括iframe和canvas等,不同源的iframe禁止数据交互,含有不同源数据的canvas会受到污染而无法进行操作
  • xmlHttpRequest同源策略:简单点讲就是禁止不同源的ajax请求,主要用来防止CSRF的攻击

    跨域请求的方式

  • jsonp(这种方式主要是利用了script/img/iframe的src可以请求不同源的数据文件的特点)
  • CORS(这种是官方提供的方法,在很多浏览器上也是兼容的,IE10以上)

    CORS

    也叫“跨域资源共享”,这个标准定义了跨域访问资源时浏览器和服务器要怎么通信,通俗讲就是跨域访问的时候浏览器的header会附加一些头信息与服务器进行沟通。其实CORS背后的思想就是通过自定义Http头部让浏览器和服务器进行沟通。跨域主要分为简单请求非简单请求
  1. 简单请求
    请求方式是get/post/head
    头信息是一下字段之一:Accept/Accept-Language/Content-Language/Content-type(不包括application/json)
    当浏览器识别到这个请求是简单请求的时候,就会在头信息附加上一个origin字段,这个头信息会把这次请求的(协议+域名+端口)传递给服务器,服务器会检查这个请求的来源。要是服务器同意了这个来源呢,在正常回复浏览器的同时,就也附加上几条字段作为回礼:
    1
    2
    Access-Control-Allow-Origin // 这条写着服务同意的来源,或者一个代表所有来源的 “*”
    Access-Control-Allow-Credentials // 这条写着浏览器可以发Cookie过来了总的来说得到服务器的认可了,这样浏览器就能正常收到回应了

要是不同意,服务器就正常返回数据,啥也不附加,浏览器见不到Access-Control-Allow-Origin会不高兴的,然后就不给你返回的数据了,再然后就是报错

  1. 非简单请求
    这种请求的主要方式是为put/delete,头信息可能为application/json,但是这个过程浏览器与服务器之间的交互会多了一次预检请求,以options的请求方式发送请求,头信息包括origin字段,同时还有Access-Control-Request-Header(这条是浏览器跨域请求的时候要额外附加的信息)和Access-Control-Request-Methods(这条是告诉服务器等会的跨域请求是啥方式)
    服务器收到预检请求提交过来的信息后,也会严格一点,不仅检查来源,还检查请求方式和头信息字段。要是服务器同意了,就在正常的HTTP回应中附加上Access-Control-Allow-Origin字段,也同样写着服务同意的来源。这就代表这拿到服务器的认可了,毕竟是经历过严格检查的,接下来的每次跨域请求都会正常进行。要是不同意,服务器也是啥都不附加地正常回应,这个时候浏览器看不见Access-Control-Allow-Origin可是会生气的,连跨域请求都懒得发,直接报错。

    JSONP

    JSONP 是 JSON with padding(填充式 JSON 或参数式 JSON )的简写,是应用 JSON 的一种新方法。JSONP 的原理非常简单,为了克服跨域问题,利用没有跨域限制的 script 标签加载预设的 callback 将内容传递给 JavaScript。
    1
    2
    3
    4
    5
    6
    7
    function handleResponse(response){
    alert("You're at IP address " + response.ip + ", which is in " + response.city + ", " + response.region_name);
    }

    var script = document.createElement("script");
    script.src = "http://freegeoip.net/json/?callback=handleResponse";
    document.body.insertBefore(script, document.body.firstChild);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//jQuery实现跨域
<script>
function doSomething(jsonData) {
alert('doSomething ' + jsonData.status);
}
$.ajax({
type: "get",
url: 'http://localhost:8002/jsonp',
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback: "doSomething",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function (json) {
alert(json.status);
},
error: function () {
alert('fail');
}
});
</script>

postMessage

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//a.html
<script>
function onLoad() {
var iframe = document.getElementById('iframe');
var win = iframe.contentWindow;
win.postMessage("我来自页面a", "*");
}
</script>
<iframe id="iframe" src="b.html" onload="onLoad()"></iframe>
//b.html
<script>
window.onmessage = function (e) {
e = e || event;
alert(e.data);
}
</script>

参考文章

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器