学习AJAX跨域获取数据碰到这个问题,特此记录。
理解跨域首先必须要了解同源策略。同源策略是浏览器上为安全性考虑实施的非常重要的安全策略。
同源是什么?
URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。
为什么需要同源?
假设从一个恶意网站打开支付宝或其他重要的页面(通过window.open),如果没有同源限制,恶意网页上的javascript脚本就可以任意操作你打开的支付宝等网页,这是极其危险的。
由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,当你试图请求不同域的资源时,浏览器会发出如下警告。
如果我们真的需要跨域请求,该怎么做呢?
1)很明显,根据浏览器提示,CORS头缺少....这个CORS是什么东西?
跨域资源共享(CORS )是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源。而这种访问是被同源策略所禁止的。CORS系统定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。 它是一个妥协,有更大的灵活性,但比起简单地允许所有这些的要求来说更加安全。
简而言之,CORS就是能实现跨域访问的一种方法。只需要服务器响应头Access-Control-Allow-Origin中含有发起请求的域,就可跨域获取资源。
如图,响应头中Access-Control-Allow-Origin设置为*,意味着所有的域都可以访问该资源。如果是自己的服务器,设置为具体的域即可。
这种方法虽然简单,但需要通过服务器后台进行设置,如果没有权限修改后台数据,就不能获取到数据了。
2)jsonp
jsonp是json数据的一种使用方式。为什么通过jsonp就能跨域请求呢?
在写平常的html中,我们发现,Web页面上调用js文件时是不受跨域的影响,例如调用CDN。不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力(script,img..)。
因此我们可以利用这个特性,设置script标签的src属性为给定数据的URL,当发起请求时,让服务器将数据装入js脚本文件中并返回这个脚本文件,这样客户端就获得了这一段数据。而其中的难点就在于怎样把数据装入js文件中。
它的原理其实是这样的,首先在客户端注册一个回调函数,用来接收返回的数据。然后把函数名字传给服务器。服务器将所需要的数据打包成JSON,通过字符串连接,把传递过来的函数名,JSON数据拼接成函数调用的形式。注意!这是一个js脚本文件,因此当该文件被客户端加载时,会立即执行这个函数,相当于用函数把数据包裹着传递给客户端。
下图代码是通过JSONP从百度获取关键字信息的函数
//keyword为搜索框输入的关键字 function getJson(keyword) { //cb为回调处理函数名,wd是输入的关键字,其他参数不用理会 var url="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=" +keyword+"&json=1&p=3&cb=jsonCallback"; var sc = document.createElement(‘script‘);//动态创建script标签 sc.src=encodeURI(url); //引用服务器加载的js代码 document.body.appendChild(sc); //添加结点 sc.remove(); //执行完毕后马上删除 } //回调处理函数 function jsonCallback(obj) {for(var tmp in obj) { console.log(result[tmp]) } }
输入关键字"我",发送请求,查看百度服务器响应正文
可以发现它返回的就是一个函数调用,函数名是我们传递给服务器的参数,形参是JSON数据,这段代码返回后会立即执行。
JQuery对jsonp进行了封装,可以通过以下方式调用
//第一种 $.getJSON(url,function(value,status) { console.log(value); console.log(status) }) $.ajax({//第二种 type: "get", async: false, url: encodeURI(url), dataType: "jsonp",//如果写为json 会生成一个随机的函数名字替换掉URL中第二个? jsonp: "cb",//后台定义的回调函数标识符(一般默认为:callback) jsonpCallback: "jsonCallback",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名 success: function(data,status){ console.log(data) }, error: function(){ alert(‘fail‘); } });
关于同源策略
除了AJAX XMLHttpRequest请求,存在同源策略的地方还有:跨frame脚本,跨window脚本,cookie访问。
但是Cookie中的同源只关注域名,忽略协议和端口。所以https://localhost:8080/和http://localhost:8081/的Cookie是共享的