之前在开发实验室的一个云服务,主要后端是使用java基于jfinal框架。我们在开发中遇到了一个小小的问题,由于我们开发通常是将前后端分离利用AJAX进行交互的。但是AJAX是不允许跨域的哦,那么问题来了,我们该如何进行跨域AJAX呢?
一、什么是AJAX?
Asynchronous JavaScript and XML (Ajax ) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术。Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest
函数获取数据,它是一种 API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器。Ajax 也是许多 mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序。
二、为什么会有这个问题?
ajax本身实际上是通过XMLHttpRequest对象来进行数据的交互,而浏览器出于安全考虑,不允许js代码进行跨域操作,所以会警告。
三、常见解决办法
(1)使用script标签。
script调用没有域的限制,我们可以将输出的数据伪装成script的变量。
(2)服务端脚本中转
服务端脚本使用XMLHTTP没有域的限制,但是耗费服务器的资源。
(3)利用iframe
在同一个域名的各个子域名下,如果设置了document.domain,那么是可以相互调用JS的。
(4)JSONP
这个方法也是最解决正常AJAX和多人使用的。
JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
首先在客户端注册一个callback, 然后把callback的名字传给服务器。
此时,服务器先生成 json 数据。
然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp.
最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)。
(5)CORS
这也是我们这次采用的解决办法。
CORS-CrossOrigin Resources Sharing,也即跨源资源共享,它定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。它是一个妥协,有更大的灵活性,但比起简单地允许所有这些的要求来说更加安全。简言之,CORS就是为了让AJAX可以实现可控的跨域访问而生的。
但是CORS也具有一定的风险性,比如请求中只能说明来自于一个特定的域但不能验证是否可信,而且也容易被第三方入侵。
四、在jfinal中使用CORS
在jfinal中使用cors非常简单,这是得益于有cors的支持库。我们也将这个支持库上传到了我们的CDN服务器上。
下载地址:http://cdn.besdlab.cn/cors-lib.rar
(1)在开发项目中加入支持库
(2)修改web.xml,增加以下代码
<filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.allowOrigin</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
注意cors的拦截需要在jfinal之前!
(3)使用例子,我们这里用的是jQuery,其它框架类似。
$("#login").click(function() { $.ajax("http://测试地址", { type: "POST", xhrFields: { withCredentials: true, useDefaultXhrHeader: false }, data: { username: "测试", password: "测试" }, crossDomain: true, success: function(data, status, xhr) { } }); });
五、总结
cors这种解决方案不知道是为什么在国内很少能看到,甚至于百度搜索时都搜不到。我们实验室也在尝试着使用这项技术解决跨域问题,如果大家有什么更好的办法或者是遇到了问题我们可以一起探讨和解决哦!