基于JQuery、Jsonp与Jersey的跨域访问
2014-02-14 10:09
441 查看
基于JQuery、Jsonp与Jersey的跨域访问
由于项目中模块比较多,所以需要使用多机进行分组部署,由此就带来了跨域访问的问题。
在本项目中,采用了前后端分离的技术,前端基于JQuery框架,通过自定义的组件,实现界面的开发;后端采用SpringFramework与Jersey结合的方式,由SpringFramework的MVC提供页面导航功能,有Jersey提供REST服务。
由于同源策略,一般来说位于 server1.example.com 的网页与不是 server1.example.com 的服务器沟通,而 HTML 的 <script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
从 1.2 版本开始,JQuery就提供了对 JSONP 回调的本地支持。通过指定JSONP回调,就可以加载位于另一个域的 JSON 数据。回调的语法为:url?callback=?。
jQuery会自动将 ? 替换为要调用的生成函数名。如下面的例子:
JQuery会自动的将?替换为一个js函数名,并在服务器返回数据时,执行此函数,以获取服务器返回的数据。
另外一种方式,就是使用JQuery的$.ajax方法:
JQuery会根据jsonp的数据,动态的在url上附加相应的参数,构建出如上一个例子中的url。
Glassfish、Weblogic Server都使用Jersey作为JAX-RS实现。
关于REST相关的内容,可以在互联网上找到很多,在此不做说明。
Jersey提供了相应的模块,可以方便的与SpringFramework进行集成。
服务器端使用标准的Jersey标记实现服务:
由于本次测试只能在一台笔记本上进行,为了模拟出跨域的效果,需要做一些配置。具体的做法是,修改系统的hosts文件,在Windows系统上,hosts文件位于%windir%/System32/Drivers/etc/目录下。本次测试中,定义了www.example1.com和www.example2.com两个域名,配置如下:
因此如果要实现Jersey对Jsonp的支持,就需要对Jersey执行结果前后进行封装,即:
1. 在Jersey结果返回前,返回jsonpCallback参数指定的字符串及一个”(”字符
2. 在Jersey结果返回后,额外添加一个”)”字符
根据上面的分析,对于熟悉J2EE架构的人来说,一个直接的念头,就是通过添加一个filter,拦截Jersey服务的调用,并在调用前后,分别输出相应的内容。
沿着这条思路,功能的实现将会非常的简单:
1. 背景
在北京地铁数据中心的项目中,有一个中心的数据提供模块,为其他模块提供数据查询服务。由于项目中模块比较多,所以需要使用多机进行分组部署,由此就带来了跨域访问的问题。
在本项目中,采用了前后端分离的技术,前端基于JQuery框架,通过自定义的组件,实现界面的开发;后端采用SpringFramework与Jersey结合的方式,由SpringFramework的MVC提供页面导航功能,有Jersey提供REST服务。
1.1 Jsonp
Jsonp(JSON with Padding)是资料格式 json 的一种“使用模式”,可以让网页从别的网域获取资料。由于同源策略,一般来说位于 server1.example.com 的网页与不是 server1.example.com 的服务器沟通,而 HTML 的 <script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
1.2 JQuery的Jsonp实现
大多数的js框架都提供了Jsonp的实现,由于本次项目选择使用了JQuery,因此只介绍一下JQuery对Jsonp的实现。从 1.2 版本开始,JQuery就提供了对 JSONP 回调的本地支持。通过指定JSONP回调,就可以加载位于另一个域的 JSON 数据。回调的语法为:url?callback=?。
jQuery会自动将 ? 替换为要调用的生成函数名。如下面的例子:
jQuery.getJSON("http://www.example2.com:8080/rest/json?callback=?", function(data) { alert("Symbol: " + data.symbol + ", Price: " + data.price); }); |
另外一种方式,就是使用JQuery的$.ajax方法:
$.ajax({ type : "get", async:false, url : "http://example2.com:8080/app2/rest/json", dataType : "jsonp",//数据类型为jsonp jsonp: " callback",//服务端用于接收callback调用的function名的参数 success : function(data){ $("#showcontent").text("Result:"+data.result) }, error:function(){ alert('fail'); } }); |
1.3 Jersey
Jersey是一个REST框架,Jersey项目是Oracle项目支持的一个开源JAX-RS实现,用于构建RESTfull服务。Glassfish、Weblogic Server都使用Jersey作为JAX-RS实现。
关于REST相关的内容,可以在互联网上找到很多,在此不做说明。
Jersey提供了相应的模块,可以方便的与SpringFramework进行集成。
2. 实现
2.1 环境搭建
关于客户端的内容,由于过于简单,因此不做过多说明,本次测试使用的例子如下:<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>跨域访问示例</title> <script type="text/javascript" src="jquery-1.8.1.js"></script> <script type="text/javascript"> $(function(){ $.ajax({ type : "get", async:false, url : "http://www.example2.com:8080/app2/rest/json?sid=1494&busiId=101", dataType : "jsonp",//数据类型为jsonp jsonp: "jsonpCallback",//服务端用于接收callback调用的function名的参数 success : function(data){ $("#showcontent").text("Result:"+data.result) }, error:function(){ alert('fail'); } }); }); </script> </head> <body> <div id="showcontent">Result:</div> </body> </html> |
package com.neusoft.education.web.rest.resources; import java.util.HashMap; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.springframework.stereotype.Component; @Component @Path("/json") public class Json { @GET @Produces("application/json") public Map<String,String> test(@QueryParam("sid")String sid , @QueryParam("busiId")String busiId) { Map<String,String> map = new HashMap<String,String>(); map.put("result", "sid=" +sid + "&busiId=" + busiId); return map; } } |
由于本次测试只能在一台笔记本上进行,为了模拟出跨域的效果,需要做一些配置。具体的做法是,修改系统的hosts文件,在Windows系统上,hosts文件位于%windir%/System32/Drivers/etc/目录下。本次测试中,定义了www.example1.com和www.example2.com两个域名,配置如下:
127.0.0.1 www.example1.com 127.0.0.1 www.example2.com |
2.2 功能实现
按照Jsonp的要求,服务器端返回的结果,需要通过由jsonpCallback参数指定的字符串为名称的js函数进行调用。因此如果要实现Jersey对Jsonp的支持,就需要对Jersey执行结果前后进行封装,即:
1. 在Jersey结果返回前,返回jsonpCallback参数指定的字符串及一个”(”字符
2. 在Jersey结果返回后,额外添加一个”)”字符
根据上面的分析,对于熟悉J2EE架构的人来说,一个直接的念头,就是通过添加一个filter,拦截Jersey服务的调用,并在调用前后,分别输出相应的内容。
沿着这条思路,功能的实现将会非常的简单:
package com.neusoft.education.web.filter; import java.io.IOException; import java.io.OutputStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebFilter("/rest/*") public class JsonpFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { String jsonCallback = ((HttpServletRequest)req).getParameter("jsonpCallback"); if (jsonCallback != null) { HttpServletResponse response = (HttpServletResponse)res; OutputStream os = response.getOutputStream(); os.write((jsonCallback + "(").getBytes()); chain.doFilter(req, res); os.write(")".getBytes()); } else { chain.doFilter(req, res); } } public void init(FilterConfig fConfig) throws ServletException { } } |
3. 限制
由于Jsonp本质上是通过动态<script> tag实现的,因此Jsonp只能支持GET方式的请求。相关文章推荐
- JQuery -- Dom操作, 示例代码
- JQuery -- Dom操作, 示例代码
- jQuery EasyUI - Add link to datagrid cell
- jquery 导航固定的一个实例
- jquery中的$(document).ready()使用小结
- jquery easyui 操作总结
- 10个最好的 jQuery 视频插件
- jquery获取tr并更改tr内容
- jquery获取元素索引值index()
- jquery中的$(document).ready()使用小结
- jQuery获取和设置表单元素的方法
- jquery中交替点击事件的实现代码
- bxSlider——焦点幻灯响应式jQuery插件
- jQuery学习基础知识小结
- jquery hover下拉菜单导航仿京东商城商品分类导航样式
- 收集国内国外最全最好的 jquery前端好站
- JQuery一个页面多个form提交
- 一个关于jquery easyui crud demo 的一个例子
- JQuery扩展插件Validate 5添加自定义验证方法
- jquery基本用法