什么是跨域:
浏览器同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
与一个不满足同源策略的域的页面进行交互,就是跨域。
跨域三种方案:
1. ifram标签
html中有一些标签不受同源策略限制,ifram就是其中一个。
2. postMessage
属于h5新增api。
3. JSONP
最常用的就是JSONP,也是面试中最常考的。JSONP简单来说就是动态生成js脚本。这里需要服务端配合,调用者可以传一个参数过去告诉服务端 “我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来生成js脚本并响应了。
示例代码:
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
最终服务器端生成的返回给请求页面的代码段应该是这样的:
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
jsonp乍看给ajax很像,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装。
jquery实现jsonp:
jQuery(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
},
error: function(){
alert('fail');
}
});
});
但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加。
JSONP常考面试题:
手写jsonp:
var jsonp = function(url,param,callback){
//处理url地址,查找?,如果没有?这个变量就有一个"?",有?这个变量接收一个&
var querystring = url.indexOf("?") == -1?"?":"&";
//处理参数{xx:xx}
for(var k in param) {
querystring += k + "=" + param[k] + '&';//?k=para[k]
}
//处理回调函数名
var random = Math.random().toString().replace(".","");
var cbval = "my_jsonp" + random;
var cb = "callback="+cbval;
querystring += cb;
var script = document.createElement("script");
script.src = url + querystring;
//挂载回调函数
window[cbval] = function(data) {
//这里执行回调的操作,用回调来处理参数
callback(data);
//拿到了就删掉这个script
document.body.removeChild(script);
};
document.body.appendChild(script);
}
jsonp(
"https://www.baidu.com",
{aa:11},
function(){
console.log(param);
}
);