Ajax跨域请求解决方案:JSONP原理与Java后台实现
本文详细解析Ajax跨域请求的JSONP解决方案。通过Java后台接收callback参数并封装JSON数据,前端利用script标签src无跨域限制的特性,指定dataType为jsonp进行请求。文章涵盖后台实现代码、前台两种调用写法及JSONP工作原理,帮助开发者解决跨域数据交互问题。
近期在进行公众号前台开发时,遇到了Ajax跨域请求的难题。诸如省-市-县三级联动、汽车品牌-车系-车款三级联动查询等功能,均需调用外部接口(其他工程项目的接口)来完成。在此分享个人在后台开发人员协助下总结的跨域请求解决方案,旨在记录积累并供参考,欢迎提出意见或建议。
解决跨域请求需借助后台代码接收callback回调函数,并对JSON数据进行相应处理;前台则通过Ajax向服务器发送包含callback参数的请求,并将数据格式指定为JSONP。
一、后台对跨域请求进行处理
以CarBrandController.java(汽车品牌接口Java文件)为例,该方法主要根据level值查询对应的品牌、车系或车款。在此需处理跨域请求的回调函数接收:若返回的callback为null,则非跨域请求,无需特殊处理,直接打印JSON接口数据即可;若callback不为null,则表明是跨域请求,需对JSON数据进行特殊处理,即在JSON数据外层添加一对小括号包裹,具体实现见HttpAdapter.java文件中的printlnJSONObject方法。
public void json(HttpServletRequest request,HttpServletResponse response){
Map<String,Object>map=new HashMap<String, Object>();
String id = request.getParameter("id"); //接收ajax请求带过来的id
String level = request.getParameter("level"); //接收ajax请求带过来的level
String callback=request.getParameter("callback"); //接收ajax请求带过来的callback参数
if ("1".equals(level)) { //如果level是'1',则查询第一级目录内容
map.put("results", this.carBrandService.findByAttr(null, "first_letter asc")); //调用查询方法,结果放入map
} else if ("2".equals(level)) { //如果level是'2',则查询第二级目录内容
map.put("results", this.carSerieService.findByAttr("parent_id="+id, "first_letter asc"));//调用查询方法,结果放入map
} else if ("3".equals(level)) { //如果level是'3',则查询第三极目录内容
map.put("results", this.carModelYearService.findByAttr("parent_id="+id, "jian_pin desc"));//调用查询方法,结果放入map
}
map.put("level",level);
if (null==callback) { //如果接收的callback值为null,则是不跨域的请求,输出json对象
HttpAdapter.printlnObject(response, map);
}else{ //如果接收的callback值不为null,则是跨域请求,输出跨域的json对象
HttpAdapter.printlnJSONPObject(response, map, callback);
}
}
在HttpAdapter.java(输出对象Java文件)中,printlnObject方法用于打印正常的JSON字符串;而printlnJSONObject方法则对JSON字符串进行了特殊处理以支持跨域。
/**
* 打印对象
* @param response
* @param object
*/
public static void printlnObject(HttpServletResponse response,Object object){
PrintWriter writer=getWriter(response);
writer.println(JSON.toJSONString(object));
}
/**
* 打印跨域对象
* @param response
* @param object
*/
public static void printlnJSONPObject(HttpServletResponse response,Object object,String callback){
PrintWriter writer=getWriter(response);
writer.println(callback+"("+JSON.toJSONString(object)+")");
}
二、前台ajax跨域请求数据
写法1:向服务器发送参数callback=?,同时指定dataType为'jsonp'格式。跨域请求时,指定的数据格式必须为JSONP形式。
function loadData(obj,level,id,value){
$.ajax({
url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id+'&callback=?', //将callback写在请求url后面作为参数携带
type:'GET',
async:false,
dataType:'jsonp',
success:function(data){
console.log(data);
//其他处理(动态添加数据元素)
});
}
写法2:callback无需写在url中,但需指定jsonp参数为'callback',并给jsonpCallback参数赋予一个值。
function loadData(obj,level,id,value){
$.ajax({
url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id,
type:'GET',
dataType:'jsonp',
jsonp: 'callback', //将callback写在jsonp里作为参数连同请求一起发送
jsonpCallback:'jsonpCallback1',
success:function(data){
console.log(data);
}); }
上述两种写法含义相同,仅表现形式不同。
接下来补充JSONP的工作原理。
三、jsonp跨域的原理解析
JSONP的基本原理是动态添加一个<script>标签,由于script标签的src属性不受跨域限制,因此可实现跨域访问。这种方式与Ajax XmlHttpRequest协议无关。
JSONP是一个非官方协议,允许服务器端集成Script tags返回至客户端,通过javascript callback形式实现跨域访问JSONP(JSON with Padding)。受同源策略限制,XmlHttpRequest仅允许请求当前源(域名、协议、端口)的资源。通过HTML script标记进行跨域请求,并在响应中返回执行的script代码(可直接使用JSON传递JavaScript对象),这种跨域通讯方式称为JSONP。
jsonCallback函数jsonp1236827957501(....)是浏览器客户端注册的,用于在获取跨域服务器上的JSON数据后执行回调。
JSONP原理如下:
首先在客户端注册一个callback(如:'jsoncallback'),然后将该callback的名字(如:jsonp1236827957501)传给服务器。注意:服务端得到callback数值后,需用jsonp1236827957501(......)将待输出的JSON内容包裹起来,此时服务器生成的JSON数据才能被客户端正确接收。
随后以JavaScript语法生成一个function,function名字即为传递上来的参数'jsoncallback'的值jsonp1236827957501。
最后将JSON数据直接以入参方式放置到function中,从而生成一段JavaScript语法文档并返回给客户端。
客户端浏览器解析script标签,并执行返回的JavaScript文档。此时JavaScript文档数据作为参数,传入客户端预先定义好的callback函数(如上例中jQuery $.ajax()方法封装的success: function (json))中(动态执行回调函数)。
可以说JSONP的方式原理上与<script src="http://跨域/...xx.js"></script>一致(QQ空间大量采用此方式实现跨域数据交换)。JSONP是一种脚本注入(Script Injection)行为,因此存在一定的安全隐患。
注意,jQuery不支持通过POST方式进行跨域请求。
定制 Quill.js 主题样式:修改默认 CSS 与添加自定义类名
2026-11-04 11:21:35
混淆JS代码怎么在线反混淆并格式化阅读
2026-11-03 21:46:39
JS在线编辑器代码报错怎么调试?控制台使用技巧
2026-11-03 21:24:56
从 marked.js 旧版本升级到最新版:API 变更与迁移指南
2026-11-03 17:38:17
JS富文本编辑器Quill与代码编辑器CodeMirror的区别及应用场景
2026-11-03 16:52:09
