一.什么是CORS
CORS - cross-origin resource sharing,即跨域资源共享。为什么有这个概念,首先介绍同源策略。
同源策略 - URL由协议、主机名、端口和路径组成,如果两个URL的协议、主机名和端口相同,则表示同源。浏览器的同源策略,限制了来自不同源的文档或脚本,对当前文档读取或设置某些属性。 简而言之就是浏览器出于网站安全性的考虑,限制不同源之间的资源相互访问的一种策略。 以下操作具有同源策略的限制: (1)Ajax请求不能发送; (2)无法获取DOM元素并进行操作; (3)无法读取Cookie、LocalStorage 和 IndexDB.二.CORS的影响
有过前后端开发的童鞋可能遇到过下面的情况:项目前后端分离的情况下开发的,Ajax请求本地开发的时候OK,为什么和同事联调的时候就出现问题?
因为CORS限制了不同源的Ajax请求不能发送。
三.解决JSON跨域Ajax请求的方案
1.设置Access-Control-Allow-Origin属性
在HTTP的请求头中有一个Origin的头信息:表示请求的来源。在服务端的响应头里面对应有一个Access-Control-Allow-Origin的头信息:表示接受的跨域请求来源。假如这两个信息不一致,请求不会被接受。
记得毕设的时候遇到过这个问题,当时前端请求的时候,后台返回 "No 'Access-Control-Allow-Origin' header is present on the requested resource." 如果解决这个问题?在服务端加上Access-Control-Allow-Origin-xxx的设置。 在Git上找到了当时上传的代码片段:response.setHeader("Access-Control-Allow-Credentials", "true");// 证书可用 response.setHeader("Access-Control-Allow-Methods", "GET,PUT");// 允许哪些HTTP方法可用 response.setHeader("Access-Control-Allow-Origin", "*");// 允许哪些域名可用,这里设置的是通配符,表示所有域名都允许 response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type");// 允许哪些头部信息是可用的 response.setHeader("Access-Control-Max-Age", "30");// 指定本次预检请求的有效期,单位为秒。在有效期间,不用发出另一条预检请求
这种方式可以防止CSRF(跨站请求伪造)攻击。
2.JSONP
维基百科解释:
JSONP(JSON with Padding)是数据格式JSON的一种'使用模式',可以让网页从别的域名要数据。另一个解决这个问题的新方法是跨域资源共享。由于同源策略,一般来说位于server1.example.com的网页无法与 server2.example.com的服务器沟通,而HTML的 <script>元素是一个例外。利用 <script>元素的这个开放策略,网页可以得到从其他来源动态产生的JSON数据,而这种使用模式就是所谓的 JSONP。用JSONP抓到的数据并不是JSON,而是任意的JavaScript,用 JavaScript解释器运行而不是用JSON解析器解析。
"padding" 意为内联,就是将JavaScript加入JSON文档。内联与JSON文档的JavaScript调用一个函数,函数参数是JSON。函数参数提供了一种将数据传递给函数的方式。
一份JSON文件并不是一个JavaScript程序。为了让浏览器可以在 <script>元素运行,从src里URL 回传的必须是可执行的JavaScript。服务器会在传给浏览器前将JSON数据填充到回调函数中。浏览器得到的回应已不是单纯的数据叙述而是一个脚本。 该URL回传的是由函数调用包起来的动态生成JSON,这就是JSONP的"填充(padding)"的由来。 虽然这个填充是浏览器运行背景中定义的某个回调函数,它也可以是变量赋值、if叙述或者是其他JavaScript叙述。JSONP要求(也就是使用JSONP模式的请求)的回应不是JSON也不被当作JSON解析——回传内容可以是任意的表达式,甚至不需要有任何的JSON,不过惯例上填充部分还是会触发函数调用的一小段JavaScript片段,而这个函数调用是作用在JSON格式的数据上的。 原理: 在页面中插入一个script标签,创建_callback方法,通过服务器配合执行_callback方法,并传入一些参数。实际上并不是Ajax请求。 (1)客户端利用script标签可以跨域请求资源的性质,向网页中动态插入script标签,来向服务端请求数据; (2)服务端会解析请求的url,拿到回调函数(比如callback=testCallback)参数,之后将数据放入其中返回给客户端; (3)jsonp不同于平常的ajax请求,它仅仅支持GET类型的方式。简单示例:
页面:var url='http://www.baidu.com/"+"?callback=?'; $.ajax({ url:url, dataType:'jsonp', processData: false, type:'get',// JSONP只能使用GET success:function(data){ // to do }, error:function(XMLHttpRequest, textStatus, errorThrown) { // to do }});
后台代码:
String callbackName = (String) request.getAttribute("callback"); String json = ESBJSONUtil.objToJsons(results).toString(); String renderStr = callbackName+"("+json+")";// 用参数callbackName在json外面再套一层,就变成了jsonp response.setContentType("text/html"); response.setCharacterEncoding("utf-8"); response.getWriter().write(renderStr);jQuery里面还有一种插件— 。
3.代理
可以通过 Nginx 或者 httpd 拦截请求,使之在同一个 domain 下面,代理访问,避免跨域问题。