解决js ajax跨域问题

作者:张雨

什么是跨域问题?

跨域问题来源于JavaScript的”同源策略”,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。跨域问题是针对JS和ajax的,html本身没有跨域问题。

  1. http://www.abc.com/a/b 调用 http://www.abc.com/d/c(非跨域)
  2. http://www.abc.com/a/b 调用 http://www.def.com/a/b (跨域:域名不一致)
  3. http://www.abc.com:8080/a/b 调用 http://www.abc.com:8081/d/c (跨域:端口不一致)
  4. http://www.abc.com/a/b 调用 https://www.abc.com/d/c (跨域:协议不同)

注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

解决方法:

  1. JSONP方式解决跨域问题
    jsonp解决跨域问题是一个比较古老的方案(实际中不推荐使用),这里做简单介绍(实际项目中如果要使用JSONP,一般会使用JQ类库等对JSONP进行了封装的类库来进行ajax请求)

    jsonp的核心则是动态添加 <script> 标签来调用服务器提供的 js脚本。

    `$.ajax({
    url: ‘http://localhost/index.php', //不同的域
    type: ‘GET’, // jsonp模式只有GET 是合法的
    data: {

    'action': 'aaron'

    },
    dataType: ‘jsonp’, // 数据类型
    jsonp: ‘jsonpCallback’, // 指定回调函数名,与服务器端接收的一致,并回传回来
    })
    `

    其实jquery 内部会转化成

    http://localhost/index.php?jsonpCallback=jQuery202003573935762227615_1402643146875&action=aaron

    然后动态加载

    <script type="text/javascript"src="http://localhost/index.php?jsonpCallback= jQuery202003573935762227615_1402643146875&action=aaron"></script>

    然后后端就会执行jsonpCallback(传递参数 ),把数据通过实参的形式发送出去。
    使用JSONP 模式来请求数据的整个流程:客户端发送一个请求,规定一个可执行的函数名(这里就是 jQuery做了封装的处理,自动帮你生成回调函数并把数据取出来供success属性方法来调用,而不是传递的一个回调句柄),服务器端接受了这个 jsonpCallback函数名,然后把数据通过实参的形式发送出去

  2. CORS解决跨域问题

    CORS请求原理 CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
    浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求。

    如何判断是否是简单请求?

    浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求。

    • 请求方法是以下三种方法之一:HEAD,GET,POST

    • HTTP的头信息不超出以下几种字段:

      Accept Accept-Language Content-Language Last-Event-ID Content-Type(只限于三个值application/x-www-form-urlencoded、 multipart/form-data、text/plain)

      凡是不同时满足上面两个条件,就属于非简单请求。

      • PHP后台配置
    1. 允许单个域名访问
      header('Access-Control-Allow-Origin:http://test.com');

    2. 允许多个域名访问
      $origin = isset($_SERVER['HTTP_ORIGIN'])? $_SERVER['HTTP_ORIGIN'] : ''; $allow_origin = array( 'http://test1.com', 'http://test2.com' ); if(in_array($origin, $allow_origin)){ header('Access-Control-Allow-Origin:'.$origin); }

    3. 允许所有域名访问
      header('Access-Control-Allow-Origin:*'); header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支持的http 动作 header('Access-Control-Allow-Headers:x-requested-with,content-type'); //响应头 请按照自己需求添加。

  3. 代理请求方式解决跨域问题

    这种方式是通过后台(ASP、PHP、JAVA、ASP.NET)获取其他域名下的内容,然后再把获得内容返回到前端,这样因为在同一个域名下,所以就不会出现跨域的问题。

    实现过程

    比如在广州的WEB服务器的后台(www.guangzhou.com/proxy-shanghaiservice.php)来调用上海(www.shanghai.com/service.php)的服务,然后把响应的结果返回前端,这样前端调用广州同域名的服务就和调用上海的服务效果相同了。