ajax请求总是不成功?浏览器的同源策略和跨域问题详解

场景

码农小明要做一个展示业务数据的大屏给老板看,里面包含了来自自己网站的数据和来自隔壁老王的数据。
那么自己网站的数据提供了 http://xiaoming.com/whoami 这样的数据接口
隔壁老王提供了 http://oldwang.com/isdad 这样的数据接口
单独点开都是没有问题的。但是一使用 js 的 ajax 请求就无法收到来自 oldwang.com 的数据了。
点开浏览器控制台一看,红字标出(Chrome):

XMLHttpRequest cannot load http://oldwang.com/isdad. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://xiaoming.com/' is therefore not allowed access.

这就是遇到了跨域问题

为什么会有这样的问题?

想象一下如果隔壁老王根本不认识你,他的网站自己有各种用户接口、订单接口、文章接口,那么谁都可以把这些接口返回的数据直接放在自己的网站上了,还是实时的。

所以浏览器制定了一个 同源策略 ,限制了从一个源(origin)中的脚本获取来自其他源(origin)中的资源。

什么是同源

如果两个页面拥有相同的协议(protocol: http),端口(port: 80),和主机(host: xiaoming.com),那么这两个页面就属于同一个源(origin)。

解决方案

这里就不讲多年前的iframe、flash等方式了,只讲几个最常用到的方案

A.x.com 和 B.x.com 间的跨域

子域名不同也是会受到跨域限制的。这种问题最简单,只需要将页面声明为更高级的域就可以了。

<script>
  document.domain = "x.com";
</script>

最经典、高效、浏览器兼容最好的解决方案:JSONP

但是有一个致命的缺点:非常高的跨站脚本攻击风险,所以 DataV 是不支持这种方式的

看到JSONP这个名字很多人以为这是和JSON密切相关的一种用来跨域的黑科技,但实际上从跨域的视角看,跟JSON并没有一毛钱关系,他是利用了浏览器允许跨域加载 js 等资源来获取数据。

因为浏览器支持跨域加载 js 如 <script src="http://aliyun.com/....."></script> ,所以很简单,可以把数据包装成 js 就可以了。

这是数据,通过 script 加载到数据无法“执行”,更无法传给 ajax 的回调函数:

{
  "data": 123
}

这是js脚本,只要将 callback 与 ajax 的回调函数做关联,就可以讲数据传给回调函数:

callback({
  "data": 123
})

这可以看到四点:

一、需要 callback 与 ajax 回调函数绑定;
二、需要数据服务器 配合 的。
三、只支持GET请求
四、数据服务器可以随意插入危险的脚本

前端如果用 jquery,jquery已经完成了整个取值过程的封装,逻辑是:
1. 随机生成不重复的 callback 函数名,并与 ajax 回调函数 绑定。
1. 将 callback 函数名放入 URL 的 query string 中,如 http://oldwang.com/api?callback= jQuery214015557975923291245_1460532274390
1. 生成一个 <script> 标签,将上述 URL 作为 src
1. 等待数据加载,并把数据传入 ajax 的回调函数

后端以 php 为例,逻辑是获取浏览器传来一个参数作为callback包装数据:

<?php
  echo $_GET['callback']."(". $data .")";
?>

大部分新浏览器都兼容的 CORS(Cross Origin Resource Sharing)

他的原理是隔壁老王主动告诉浏览器“别拦着小明,我们是亲戚……”
所以最简单的例子,就是在数据服务器返回的头信息中包含:

Access-Control-Allow-Origin: http://xiaming.com

然而这个头信息并不支持枚举,那如果隔壁老王的亲戚太多就只能通过程序来动态得生成这个头信息了,以PHP为例:

<?php
if (is_my_bastard($_SERVER['HTTP_ORIGIN'])) {
 header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
?>

如果老王作为一个好人,来者不拒。那么可以直接使用 *

Access-Control-Allow-Origin: *

Cookies

CORS默认是不带 cookie 信息的,如果要带上 cookie 需要添加 withCredentials 参数,以 jquery 为例:

$.ajax({
    url: "http://laowang.com/isdad",
    xhrFields: {
      withCredentials: true
    }
  });

而服务器还需要加上允许 Credentials 的头信息以及不允许用通配符“*”,如下面的代码

<?php
if (is_my_bastard($_SERVER['HTTP_ORIGIN'])) {
  header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); // 不允许用 *
  header("Access-Control-Allow-Credentials:true");
}
?>

这就是隔壁老王的故事

其他参数可以参阅:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

时间: 2025-01-30 18:27:21

ajax请求总是不成功?浏览器的同源策略和跨域问题详解的相关文章

深入浅析同源策略和跨域访问_javascript技巧

1. 什么是同源策略      理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略.     何谓同源:         URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源.    同源策略:         浏览器的同源策略,限制了来自不同源的"document"或脚本,对当前"document"读取或设置某些属性. (白帽子讲web安全[1])         从一个域上加载的脚本不允许访

javascript ajax脚本跨域调用详解

今天终于有点时间研究了一下javsscript ajax 脚本跨域调用的问题,先在网上随便搜了一下找到一些解 决的办法,但是都比较复杂.由是转到jquery.chm用户手册当中找到一些代码片段关于ajax跨域调用的问题. 代码片段如下: crossDomain   mapV1.5 默认: 同域请求为false 跨域请求为true如果你想强制跨域请 求(如JSONP形式)同一域,设置crossDomain为true.这使得例如,服务器端重定向到另一个域. 这 里强调如是ajax的跨域调用,data

通达OA 使用Ajax和工作流插件实现根据人力资源系统数据增加OA账号(图文详解)_AJAX相关

本次小飞鱼开发的程序主要解决某下属公司在人力系统中增加账号不能马上审批完毕的问题,可以通过这个流程审批后由插件在后台判断自动增加OA账号,增加机制与hr与OA系统同步相同. 只进行增加操作,没有修改.删除的操作.原有已经进行了两个系统的数据自动同步开发,因此这次的开发属于一个补充的内容,仅在此提供一个应用的思路和开发过程的探讨. 前端发起人申请时填写hr系统中已经分配的工号,即可对应查询出其他相关数据.为了避免查出数据后对工号修改,增加一个确认工号输入框.其他信息由Ajax自动获取为只读形式.这

location的hash部分和使用window.onhashchange实现ajax请求内容时使用浏览器后退和前进功能

在js跨域双向数据传递时可以用iframe加上location.hash来实现,在研究这个的时候深入学习了一下hash的特性.   hash就是uri中#及后面的部分,例如:www.google.com.hk#123的#123.当只有hash部分发生变化时,浏览器的历史记录会产生记录,但不会向服务器发出请求,这时按后退键地址栏的uri会变化但页面内容不变.   而hash变化但不发出请求就是js跨域双向数据传递的基础啦.   下面就讲述一下hash结合ajax的使用,ajax每次取数据时页面更新

Nginx实现浏览器可实时查看访问日志的步骤详解_nginx

一.首先查看nginx版本,我使用的是1.9.7的版本,安装目录在/application/nginx-1.9.7 [root@AnSheng ~]# /application/nginx-1.9.7/sbin/nginx -V nginx version: nginx/1.9.7 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC) configure arguments: --prefix=/application/nginx-1.9.7

Ajax跨域请求 JSON JSONP

同源策略和跨域-总结 目录: 1.同源策略 2.跨域 3.几种跨域技术   1.同源策略 什么叫同源? URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源.相反,只要协议,域名,端口有任何一个的不同,就被当作是跨域. e.g. 对于http://store.company.com/dir/page.html进行同源检测: URL 结果 原因 http://store.company.com/dir2/other.html 成功 仅路径不同 http://st

jquery ajax跨域请求详解

ajax要在各种浏览器下都实现完美的跨域需要借助于jsonp技术,jsonp实质是请求一个js脚本文件,在js文件载入完毕时执行某个函数,这样就可以完美的规则跨域问题了. 什么是jsonp格式呢?API原文:如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型.使用这种类型的话,会创建一个查询字符串参数 callback=? ,这个参数会加在请求的URL后面.服务器端应当在JSON数据前加上回调函数名,以便完成一个有效的JSONP请求.意思就是远程服务端

[CORS:跨域资源共享] 同源策略与JSONP

Web API普遍采用面向资源的REST架构,将浏览器最终执行上下文的JavaScript应用Web API消费者的重要组成部分."同源策略"限制了JavaScript的跨站点调用,这必然导致Web API不能垮域提供资源.如果Web API仅限于为"同源客户端"提供资源,那么它都对不起自己的名字,因为Web本身是一个开放的协议.那么ASP.NET Web API通过怎样的方式来实现跨域资源共享呢? 同源策略 浏览器是访问Internet的工具,也是客户端应用的宿主

详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】_javascript技巧

目录 一.AJAX示例 1.1.优点 1.2.缺点 1.3.jQuery AJAX示例 二.延迟对象(Deferred) 2.1.回调函数 2.2.deferred.done 三.跨域 3.1.什么是跨域 3.2.JSONP跨域 3.3.jQuery使用JSONP跨域 3.4.跨域资源共享(CORS) 3.5.小结 四.弹出层 五.模板引擎 5.1.Hello World 5.2.方法 5.3.与AJAX结合应用 六.示例下载 一.AJAX示例 AJAX全称为"Asynchronous Java