跨域
由于浏览器的同源策略(请求的url地址,必须与浏览器上的url地址处于同一域上),不在同一域下的地址不能互相访问。同源是指,域名、协议、端口号都一致。
http://google.com 和 https://google.com 不同,因为协议不同;
http://sina.com:8080 和 http://sina.com:1000 不同,因为端口不同;
http://sina.com:8080 和 https://google.com 不同,协议、域名、端口号都不同。
同源策略分为以下两种:
DOM同源策略:禁止对不同源页面DOM进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。
XMLHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。
跨域限制是为了安全性考虑。有了跨域的限制,我们访问页面就更加安全。如果没有同源策略,大家都可以随便通过ajax直接获取其他网站的信息,这样互联网就打乱了。
跨域的解决方法
<img>
的src属性(获取图片),<link>
的href属性(获取css),<script>
的src属性(获取JavaScript)这三个都不符合同源策略,它们都可以跨域获取数据。
JSONP
JSONP,即JSON with padding,是为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。
注意:JSONP只支持get请求,不支持post请求。
凡是拥有scr这个属性的标签都可以跨域,例如<script><img><iframe>
。
<script>
是没有同源限制的,就是利用src属性能够跨域访问的特性,所以可以通过<script>
访问目标地址,通过传入的回调函数callback对返回的数据进行处理并返回。
导入JSONP库,封装JSONP
import originJSONP from 'jsonp';
/**
* @export
* @param {String} url 跨域访问的地址
* @param {Object|Function} data 传递的参数对象options / callback
* @param {Function} option 回调函数,就可以拿到数据,用ES6开发,更常用的使用Promise方法而不是回调函数
*/
export default function jsonp(url, data, option) {
url += (url.indexOf('?') < 0 ? '?' : '&') + param(data);
return new Promise((resolve, reject) => {
originJSONP(url, option, (err, data) => {
if (!err) {
resolve(data)
} else {
reject(err)
}
});
});
}
function param(data) {
let url = '';
for (var k in data) {
let value = data[k] !== undefined ? data[k] : '';
url += `&${k}=${encodeURIComponent(value)}`;
}
return url ? url.substring(1) : '';
}
原生JS封装
function loadScript(xyUrl, callback){
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = xyUrl;
script.onload = script.onreadystatechange = function(){
if((!this.readyState || this.readyState === "loaded" || this.readyState === "complete")){
callback && callback();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;//人工回收内存
if ( head && script.parentNode ) {
head.removeChild( script );
}
}
};
head.insertBefore( script, head.firstChild );
}
//
var url = "http://todolist6.sinaapp.com/pages/QuickWayGetInfo.php?callback=showInfo";
loadScript(url, showInfo);
var showInfo = function(data){
console.log(data.name);
}
跨域资源共享CORS(Cross-origin resource sharing)
阮一峰老师的跨域资源共享CORS详解讲解得非常好,值得一看。
简单的说一下过程就是:
对于客户端,我们还是正常使用xhr对象发送ajax请求。
需要注意的是,我们需要设置我们的xhr属性withCredentials为true,这个属性是为了设置是否可以携带cookie,没有设置的话,cookie是带不过去的哦,设置: xhr.withCredentials = true;
对于服务器端,需要在 response header中设置如下两个字段:
Access-Control-Allow-Origin: http://www.yourhost.com
Access-Control-Allow-Credentials:true
这样,我们就可以跨域请求接口了。
代理
例如www.123.com/index.html需要调用www.456.com/server.php,可以写一个接口www.123.com/server.php,由这个接口在后端去调用www.456.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。