同源策略(Same origin Policy)
浏览器出于安全方面的考虑,只允许与同域下的接口交互。
同域指的是?
同协议:如都是http或者https
同域名:如都是http://jirengu.com/a 和http://jirengu.com/b
同端口:如都是80端口
突破同源策略 === 跨域
跨域策略:jsonp,postMessage,CORS
1.什么是 JSONP
HTML 中 script 标签可以加载其他域下的js,比如我们经常引入一个其他域下线上cdn的jQuery。那如何利用这个特性实现从其他域下获取数据呢?
可以先这样试试:
http://api.jirengu.com/weather.php">
这时候会向天气接口发送请求获取数据,获取数据后做为 js 来执行。但这里有个问题, 数据是 JSON 格式的数据,直接作为 JS 运行的话我如何去得到这个数据来操作呢?
这样试试:
http://api.jirengu.com/weather.php?callback=showData">
这个请求到达后端后,后端会去解析callback这个参数获取到字符串showData,在发送数据做如下处理:
之前后端返回数据: {"city": "hangzhou", "weather": "晴天"}
现在后端返回数据: showData({"city": "hangzhou", "weather": "晴天"})
前端script标签在加载数据后会把 「showData({"city": "hangzhou", "weather": "晴天"})」做为 js 来执行,这实际上就是调用showData这个函数,同时参数是 {"city": "hangzhou", "weather": "晴天"}。
用户只需要在加载提前在页面定义好showData这个全局函数,在函数内部处理参数即可。
function showData(ret){
console.log(ret);
}
http://api.jirengu.com/weather.php?callback=showData">
「原来这就是 JSONP(JSON with padding),总结一下:」
1. JSONP是通过 script 标签加载数据的方式去获取数据当做 JS 代码来执行
2. 提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上「包裹」这个函数名,发送给前端。换句话说,JSONP 需要对应接口的后端的配合才能实现。
JSONP
请求方:frank.com 的前端程序员(浏览器)
响应方:jack.com 的后端程序员(服务器)
请求方创建 script,src 指向响应方,同时传一个查询参数 ?callbackName=yyy
响应方根据查询参数callbackName,构造形如
yyy.call(undefined, '你要的数据')
yyy('你要的数据')
这样的响应
浏览器接收到响应,就会执行 yyy.call(undefined, '你要的数据')
那么请求方就知道了他要的数据
这就是 JSONP
【JSONP的优缺点】
优点:兼容性好(兼容低版本IE)
缺点:1.JSONP只支持GET请求; 2.XMLHttpRequest相对于JSONP有着更好的错误处理机制
2.Cross-Origin Resource Sharing C O源 R S CORS 跨域
CORS 是W3C 推荐的一种新的官方方案,能使服务器支持 XMLHttpRequest 的跨域请求。CORS 实现起来非常方便,只需要增加一些 HTTP 头,让服务器能声明允许的访问来源。
值得注意的是,通常使用CORS时,异步请求会被分为简单请求和非简单请求,非简单请求的区别是会先发一次预检请求。
【简单请求】
使用下列方法之一且没有人为设置对 CORS 安全的首部字段集合之外的其他首部字段:
GET
HEAD
POST
Access-Control-Allow-Origin: * 表明该资源可以被任意外域访问。
【非简单请求】
使用了下面任一 HTTP 方法:
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
发送真正请求前会先发送预检请求,同时携带了下面两个首部字段:
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
3.postMessage
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。