Jsonp插件
1、同域AJAX
使用 eclipse + tomcat 开发
模仿获取手机号码归属地接口,有以下主要组件:
1)TestJsonpServlet.java类返回一个封装号码信息的json数据,访问地址为:http://localhost:8080/JsonpServer/testJsonp.do
2)index.html文件,使用ajax访问后台获取号码信息后展示在页面上面

项目结构如下:

2、跨域 AJAX 失败
使用 hbuilder 开发环境,jquery 库和 index.html 可以复制前面示例中的文件
项目结构如下:

访问http://localhost:8020/AjaxJsonp/index.html页面,点击查询控制台出错:
Failed to load http://localhost:8080/JsonpServer/testJsonp.do: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8020' is therefore not allowed access.

这就是浏览器对跨域 ajax 请求的限制
3、script 标签的 src 属性可以跨域
我们经常使用 CDN 服务器上面的 js 或者 css 文件,所以 script 标签的 src 属性是可以跨域的
示例1:
修改 localhost:8020 的 index.html 文件,加一个 script 标签,去获取 localhost:8080 的一个 js 脚本,地址为 http://localhost:8080/JsonpServer/script.jsp
<script type="text/javascript" src="http://localhost:8080/JsonpServer/script.jsp"></script>
http://localhost:8080/JsonpServer/script.jsp 返回一个 alert("我是跨域的js脚本") 内容

访问 http://localhost:8020/AjaxJsonp/index.html 页面,可以看到弹出了 “我是跨域的js脚本”

示例2:
在 localhost:8020 的 index.html 文件全部 script 标签之前再加一个 script 标签,这个里面定义一个函数
1 <script type="text/javascript"> 2 function fn(data) { 3 alert(data); 4 } 5 </script>

localhost:8080 的 script.jsp 内容修改为返回一个 fn("我是跨域的js脚本,调用fn函数") 内容

访问 http://localhost:8020/AjaxJsonp/index.html 页面,可以看到弹出了“我是跨域的js脚本,调用fn函数”

示例3:
现在 localhost:8020 的 index.html 文件的 script 标签是固定写在那里的,如果我们使用按钮触发一个函数,函数里面动态地生成一个 script 插入到 head 中,是不是可以让效果更好
把示例1在 localhost:8020 的 index.html 文件加入的 script 标签的 src 删除掉,再添加 jsonp() 函数动态向 head 插入 script

按钮点击弹出 “我是跨域的js脚本,调用fn函数”

4、开发通用的 jsonp 函数
通过 3 中的几个例子,我们可以知道:
1)js中可以动态地向head插入script标签,并且src属性可以是跨域的地址
2)这个src地址可以返回一个“本地函数调用”,把需要处理的数据当做参数传递给这个函数
3)本地函数需要预先加载到内存
下面我们就可以在 localhost:8020 中开发一个 javascript 版本的通用 jsonp 访问函数
1 /** 2 * 跨域的 jsonp 请求函数 3 * 4 * url - 地址 5 * funcNameArg - 目标服务器用于获取回调函数名的请求参数名 6 * callBack - 回调函数 7 */ 8 function jsonp(url, funcNameArg, callBack) { 9 10 // 生成一个随机的函数名 11 var rnd = ""; 12 for(var i = 0; i < 10; i++) 13 rnd += Math.floor(Math.random() * 10); 14 15 rnd += "_" + (new Date()).getTime(); 16 17 var funcName = "jsonp_" + rnd; 18 19 // 把回调函数注册到window上面 20 window[ funcName ] = callBack; 21 22 // 创建script节点 23 var script = document.createElement("script"); 24 script.setAttribute("type", "text/javascript"); 25 26 if(url.indexOf("?") == -1) 27 script.setAttribute("src", url + "?" + funcNameArg + "=" + funcName); 28 else 29 script.setAttribute("src", url + "&" + funcNameArg + "=" + funcName); 30 31 // 把script节点添加到head上面 32 var head = document.getElementsByTagName("head")[0]; 33 34 head.appendChild(script); 35 36 // 把script节点移除 37 head.removeChild(script); 38 }
修改查询按钮的点击事件函数
1 var reg = /^1\d{10}$/; 2 3 function getPhoneInfo() { 4 var phone = document.getElementById("phone").value.trim(); 5 if(!reg.test(phone)) { 6 alert("请输入手机号码"); 7 return; 8 } 9 10 // 调用jsonp函数进行跨域请求获取手机归属地信息 11 jsonp( 12 "http://localhost:8080/JsonpServer/testJsonp.do?phone=" + phone, 13 "callback", 14 function(data) { 15 var phone = "phone = " + data.phone; 16 var country = "country = " + data.country; 17 var province = "province = " + data.province; 18 var city = "city = " + data.city; 19 document.getElementById("info").innerHTML = 20 phone + "<br />" + 21 country + "<br />" + 22 province + "<br />" + 23 city + "<br />"; 24 } 25 ); 26 }
修改localhost:8080的servlet代码,让其可以处理兼容jsonp请求
1 // 兼容JSONP请求 2 String callback = request.getParameter("callback"); 3 4 if (callback == null) 5 response.getWriter().print(json); 6 else 7 response.getWriter().print(callback + "(" + json + ");");
然后,我们就可以在 localhost:8020 上面跨域访问 localhost:8080 的服务了。服务端返回了一个 jsonp_6316231340_1523246571704(函数名是 jsonp 函数动态生成后传递给服务器的)函数调用

5、jquery 的 jsonp 请求
1 <script type="text/javascript"> 2 3 var reg = /^1\d{10}$/; 4 5 function getPhoneInfo() { 6 var phone = document.getElementById("phone").value.trim(); 7 if(!reg.test(phone)) { 8 alert("请输入手机号码"); 9 return; 10 } 11 12 // http://localhost:8080/JsonpServer/testJsonp.do?phone= 13 $.ajax({ 14 type:"get", 15 url:"http://localhost:8080/JsonpServer/testJsonp.do?phone=" + phone, 16 dataType: "jsonp", 17 jsonp: "callback", 18 success: function(data) { 19 var phone = "phone = " + data.phone; 20 var country = "country = " + data.country; 21 var province = "province = " + data.province; 22 var city = "city = " + data.city; 23 document.getElementById("info").innerHTML = 24 phone + "<br />" + 25 country + "<br />" + 26 province + "<br />" + 27 city + "<br />"; 28 } 29 }); 30 } 31 </script>
6、示例代码下载

浙公网安备 33010602011771号