少用但始终都会碰到 - 跨域ajax

  • 作者:KK

  • 发表日期:2017.2.15


方法1:利用HTML5新特性的支持实现

现在大家大部分都做移动Web,基本上都支持HTML5,甚至做PC端的也越来越无视旧版IE了,所以比较推荐这个

  • 前端的ajax写法就像平时获取本域名数据一样不用改

  • 被跨域请求的接口只要加上这两句话:

    header('Access-Control-Allow-Origin: http://test'); //允许指定域名的来源请求
    //header('Access-Control-Allow-Origin: *'); //还能这样允许所有来源
    header('Access-Control-Allow-Credentials: true');
    

    其实就是响应两个报头,而Access-Control-Allow-Origin的值是请求来源的网址,“http://test”是我的示例网址,实际上要换成你的真实的来源地址

    在新浏览器环境下(只要不是旧IE),当ajax发起对其它域名的请求时,其实请求是出去了,也到达了目标服务器,并使服务器上的PHP程序(或其它语言的程序)跑起来了

    但目标服务器发现来源不是本域,所以没有将PHP的运行结果回送给请求来源,而是直接响应了302状态码

    只要添加这两个报头就可以允许别人跨域请求自己,浏览器收到这个响应头后也会配合开放办事


  • 无法便捷地同时允许指定多个来源

    我暂时也没找到办法,类似下面这样同时声明多个来源都不行

    header('Access-Control-Allow-Origin: http://source1 http://source2'); 
    

    只能用*号允许来自全部的,希望只是我没找到简单的办法,如果大家找到了方法麻烦告诉我一下哦!


  • 我绕了个方法实现允许多个来源:

    $来源白名单'http://aa.com',
    	'https://bb.com',
    ];
    	
    if(isset($_SERVER['HTTP_REFERRER'])){
    	$urlInfo = parse_url($_SERVER['HTTP_REFERRER']);
    	$来源域名协议域名协议$urlInfo['scheme'];
    	$来源域名$urlInfo['host'];
    		
    	$来源首页'://' . $来源域名'Access-Control-Allow-Origin: ' . $来源首页'Access-Control-Allow-Credentials: true');
    	}
    }
    

方法2:用jsonp

为了解答大部分菜鸟的疑惑,首先这里很直白地描述一个接近jsonp的跨域数据传递实现方案:

  1. A(请求方)先定义一个类似这样的全局JS函数:

    var cityName = '';
    	
    function setData(data){
    	cityName = data;
    }
    
  2. A发起了一个GET请求去获取B(另一个域)的接口数据,希望所在城市名称

  3. B可以不管三七二十一,直接echo 'setData("江苏");',其实就是返回了一个JS代码,别管这个代码是干嘛的

  4. A相当于请求了一个JS文件,于是这个JS代码setData("江苏");自动运行了

    你想想,HTML页面可以引用非本域的JS是不是,比如直接引用 ,这是允许的,并且加载这个JS后浏览器也会自动运行这个JS源里面的代码

  5. A再执行alert('我的所在城市:' + cityName)就显示了江苏

这样就实现了A向不同域名的B获取数据了,前提是B要返回JS代码,这个代码能在A那边运行后,将数据赋值给A的储存变量;甚至B还可以返回window.cityName = '江苏';这样的代码来暴力赋值


好了这下来看看jsonp

其实jsonp的基本原理和上面是一致的,但是做法稍有不同,A向B发请求时,A构造了这么一个地址:http://bb.com/xxx.json?callback=setData

有没有发现,网上很多讲jsonp的例子都有提到callback,接下来callback是这样被B站处理响应回去的:

$callback = $_GET['callback'];
echo $callback . '("江苏")';

//于是最后输出了 setData("江苏");

这样B站就可以毫不关心A站要执行哪个函数来生成设置数据的JS代码了,反正A站将函数名称通过callback传过来,B站再拼接生成代码就是

所以jsonp的特征往往就是请求方A总是附带一个callback参数


在jQuery里实现jsonp

这个很简单,直接将dataType声明为“jsonp”就行

$.ajax({
	url : 'http://bb.com/xxx.php',
	dataType : 'jsonp',
	success : function(data){
		console.log(data);
	}
});

当dataType为jsonp时,jQuery会生成一个临时全局函数,函数的命名大概是这么长:jQuery111102055743417706435_1487088707749

然后打开浏览器Network记录一看,请求地址就是

http://bb.com/xxx.php?callback=jQuery111102055743417706435_1487088707749&_=1487088707750

其中地址后面第2个参数_是一个防缓存参数,值又是一个随机数字,因为它必须走GET请求(所有加载第三方JS代码的都是GET请求),只要URL不变都很可能被浏览器或中间的网络节点直接返回缓存,所以必须通过生成随机数来让URL不与旧的请求重复嘛,就不详解了

这下明白jQuery为什么要生成那个临时全局函数了吧,压根就是为了B方响应时拼成执行这个函数的JS代码吧,所以B方响应的结果大概就是:jQuery111102055743417706435_1487088707749(数据)