简介
由于受浏览器的同源策略(same-origin policy)的影响, Ajax 请求默认只能在同一域名下进行访问。
同源策略是浏览器安全的基石,所有的浏览器都实行了这个策略。
同源策略
同源策略是指三个相同:
- 协议相同(比如,都是 http)
- 域名相同(比如,都是 www.example.com)
- 端口相同(比如,都是 80 端口)
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取用户的数据。
如果非同源,共有三种行为受到限制:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 无法获得
- AJAX 请求不能发送
下面,我们只讲述 AJAX 请求如何规避同源策略的影响。
Ajax 的跨域场景描述
这里,我先描述一下 Ajax 的跨域场景。
在网站 http://apidemo.test ,有一个 API 接口,http://apidemo.test/api/test 。 它的路由为:
Route::get('test', function(){
return response()->json(['id'=>1, 'name'=>'test']);
});
在本网站的某个页面,也就是同源的情况下,执行的 Ajax 请求为:
$.get('http://apidemo.test/api/test', function(data){ console.log(data) });
可以得到正确的 json 响应:
{
id: 1, name: "test"}
但是,现在如果要从另外一个网站(http://adm.test)的某个页面( http://adm.test/demo ),发送 Ajax 请求到 http://apidemo.test/api/test
$.get('http://apidemo.test/api/test', function(data){ console.log(data) });
就属于 Ajax 的跨域问题,由于不同源,所以会报错:
Failed to load http://apidemo.test/api/test: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://adm.test' is therefore not allowed access.
实现 Ajax 的跨域访问
同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。
除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),还有三种方法规避这个限制。
- WebSocket
- JSONP
- CORS
WebSocket
WebSocket 是一种通信协议,使用 ws://(非加密)和 wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持 WebSocket ,就可以通过它进行跨源通信。
由于 WebSocket 很少用到,故这里不作讲述。感兴趣的可自行参考:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
JSONP
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。
JSONP (JSON with Padding)是 JSON 的一种“使用模式”,可用于解决浏览器的跨域数据访问的问题。
JSONP 的基本思想是:
- 服务器端返回的数据格式是一段可在客户端执行的 javascript 代码,形如:callback_name(json_data)
- 客户端获取该 jsonp 数据,并自动执行回调函数。
这种使用模式就是所谓的 JSONP。用 JSONP 抓到的数据并不是 JSON,而是任意的 JavaScript。
首先,我们修改服务器端 http://apidemo.test/api/test 返回的数据内容:
Route::get('test', function(){
$callback = $_REQUEST['callback']; // 获取回调函数名
$json_data = json_encode(['id'=>1, 'name'=>'test']);
return $callback . "(" . $json_data .