先创建一个xhr对象,下面代码是js高级程序设计里面给出的兼容性代码
function createXHR() {
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
}else if(typeof ActiveXObject != "undefined"){
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
for(var i=0, len=versions.length;i < len; i++){
try{
var xhr = new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
return xhr;
}catch(ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error("NO XHR object available");
}
}
var xhr = createXHR();
同域请求下,服务端不需要做多余的配置即可使用
统一使用php作为服务端,返回下列信息
if(isset($_POST['id']) && !empty($_POST['id'])){
echo json_encode(array("code" => 1, "msg" => "success", "id" => $_POST['id']));
//{"code":1,"msg":"success","id":1}
}else if(isset($_GET['id']) && !empty($_GET['id'])){
echo json_encode(array("code" => 1,"msg" => "success", "id" => $_GET['id']));
//{"code":1,"msg":"success","id":1}
}else{
echo json_encode(array("code" => 0,"msg" => "fail"));
//{"code":1,"msg":"fail"}
}
get方法的客户端
xhr.onreadystatechange = function () {
if(xhr.readyState === 4){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304){
alert(xhr.responseText);
}else{
alert("Response wa unsuccessful: " + xhr.status);
}
}
};
xhr.open('GET', "./jsonp.php?id=1", true); //异步请求
xhr.send(null); //有些浏览器是必须填null
xhr.onreadystatechange = function () {
if(xhr.readyState === 4){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304){
alert(xhr.responseText);
}else{
alert("Response wa unsuccessful: " + xhr.status);
}
}
};
xhr.open('POST', "./jsonp.php", true); //异步请求
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");//post请求增加的
xhr.send("id=1");
跨域请求即请求不同在一个域名上的请求,这里我开启了两个apache服务器端口来测试,xhr请求文件放在localhost:8008上面,php服务端放在localhost:80上面
xhr跨域请求主要是多了一个origin的header,而这部分主要在php服务端上进行设置就好,客户端的js脚本其实和同域请求并无太大区别
其中第一个是必选的
header('Access-Control-Allow-Origin:http://localhost:8008');//设置允许访问的域
header('Access-Control-Allow-Credentials: true');//设置是否发送cookie,需要在客户端同时设置才会生效
header('Access-Control-Allow-Headers:X-Requested-With');//允许的访问头部,也需要在客户端同时设置,同时为了避免跨域访问出错,客户端最好不要设置该项信息,避免服务端不允许
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE');//支持的请求方式
客户端
这里网上说了有简单跨域和复杂跨域,区别主要在请求方式和参数设置上,我就不说了,主要是我也还没理解透,可以看看利用CORS实现跨域请求
//直接是post请求
var url = "http://localhost/jsonp.php"; //我们这里的客户端代码运行在localhost:8008
xhr.open('POST', url, true);
xhr.withCredentials = true; //设置传递cookie,如果不需要直接注释就好
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); //请求头部,需要服务端同时设置
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("id=1");
以上就是cors跨域的小小实例,可以看出cors跨域支持多种请求方式
jsonp应该是第一代的跨域请求解决方案了,它的解决思路是利用script
标签上的src
属性不受跨域影响的特性解决了,就像img
标签也不受跨域影响,然后script
会请求一个服务端程序,服务端程序可以是任意语言,需要的只是返回一个使用js回调函数的字符串即可
由于客户端的回调函数名是在客户端定义的,所以服务端就必须返回与客户端的回调函数一致的函数名,为了实现动态加载的目的
php这样写
$callback = $_GET['callback'];
$code = $_GET['code'];
echo $callback."({'code':'".$code."','price':1780,'tickets':5})";
//回调函数名({'code':'传递的参数','price':1780,'tickets':5})
客户端js
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://localhost/jsonp.php?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
使用jquery实现jsonp
$.ajax({
type: "get",
url: "http://localhost/jsonp.php?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');
}
});
可以看到jsonp的实现方式其实很简单,但它的功能有一定的限制,配置项也没有cors的丰富,最重要的是jsonp只能发送GET请求,而cors可以发送GET或POST以及其他的请求