~ Ajax 跨域

Ajax 跨域的原理

Ajax 跨域问题,主要是因为浏览器的同源政策?!。首先要理解“源”的概念,可以通过「协议+域名+端口」确定一个源。

简单来讲,可以把一个项目理解为一个源。Ajax 请求可以对源内的资源发起访问,但不同源之间进行 Ajax 就会有问题。


当向不同源的资源发起 Ajax 请求时, 浏览器会加上 Origin 字段来标识源。

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Content-Length: 8
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: localhost:7070
Origin: http://localhost:9090 协议+域名+端口

服务器会根据 Origin 字段决定是否同意这次请求, 如果 Origin 指定的源不在许可范围内, 服务器会返回一个不带有Access-Control-Allow-Origin 字段的响应. 浏览器解析时发现缺少了这个字段, 就会报错。

[ Ajax 跨域的表现?! ] 这种错误不能通过状态码识别, 因为状态码很有可能就是 200。


Ajax 跨域解决方案                 

// 同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。


除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),还可以采用以下几种方式:

由于接口代理是有代价的,所以其仅是在开发过程中进行的。

与其他方法不同,CORS 是后端解决,而代理请求的方式主要是前端对接口进行代理,即:

  • 前端 Ajax 请求对是本地接口;
  • 本地接口接收到请求后向实际的接口请求数据,然后再将信息返回给前端;
  • 一般用 Node.js 或 Nginx 即可代理。

[1] CORS?!                          // CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。

它是 W3C 标准,是跨源 AJAX 请求的根本解决方法。相比 JSONP 只能发GET请求,CORS 允许任何类型的请求。


[2] JSONP              // 原理:script 元素的 src 属性不受同源政策限制,可以跨域请求(即,拥有跨域能力)

JSONP 是服务器与客户端跨源通信的常用方法,其特点是:简单适应,支持低版本浏览器,且服务器改动非常小。

[ 注意 ] 基于 JSONP 的实现原理,所以 JSONP 只能是“GET”请求,不能进行较为复杂的POST和其他请求,所以遇到类似的情况,就需要考虑跨域资源共享 CORS 或其他方案了。

它的基本思想是,网页通过添加一个 script 元素,向服务器请求 JSON 数据,这种做法不受同源政策限制,服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。


[ 实现步骤 ] 首先,网页动态插入 script 元素,由它向跨域网址发送请求(请求 JSON 数据)。

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('response data: ' + JSON.stringify(data));
};

// 请求时,接口地址是作为构建出的脚本标签的src的,这样,当脚本标签构建出来时,最终的src是接口返回的内容

上述代码通过动态添加 script 元素,向服务器 example.com 发出请求。需注意的是,该请求的查询字符串有一个 callback 参数,用来指定回调函数的名称,这对于 JSONP 是必需的。

服务器收到这个请求后,会将数据放在回调函数的参数位置返回。

// 服务端对应的接口在返回参数外面添加函数包裹层

foo({
  "test": "testData"
});

由于 script 元素请求的脚本,直接作为代码运行,所以,只要浏览器定义了 foo 函数,该函数就会立即调用。作为参数的 JSON 数据被视为 JS 对象,而不是字符串,因此避免了使用 JSON.parse 的步骤。

[ 在 jQuery 中使用 JSONP ]  在 jQuery 中使用 jsonp 技术,可以使用 ajax() 方法:

JQuery 对前台做了很好的处理,如自动生成全局回调函数等,但后台还需要开发人员自己实现。

// 前端内容
$.ajax({
       type:'get',
       url:"http://xxx.com/demo/jsonp.php",
       // url:"http://xxx.com/demo?callback=foo"
       dataType:"jsonp",   //必须指定

        // jsonp : "callback",   //自定义参数名称(等号前面的),若不指定则默认为callback
        // jsonpCallback:"foo",// 自定义回调函数的名字(等号后面的),若不指定则Jquery自己生成随机的名称
        success:function(data){
           console.log(data.username,data.password);
        }
});

// 请求URL http://xxx.com/demo?callback=foo

// 后端内容
<?php
    $cb = $_GET['callback'];
    $arr = array("username"=>"zhangsan","password"=>"123");
    echo $cb.'('.json_encode($arr)')';
?>

当 dataType 为 JSONP 时,jQuery 会为用户生成一个全局函数名称为 jsonpCallback 参数的值,这个函数内部调用了success 方法 jQuery 的实现原理及步骤;

以 GET 方式请求目标地址,并在 URL 中拼接以 jsonp 参数值为 key,以 jsonpCallback 值为 value 的参数;

请求返回回调函数数据;

触发调用全局的回调函数,在全局函数回调中调用 success 方法并将数据传递给 success 方法。