jsonp的案例
一,转发一
首先基于安全的原因,浏览器是存在同源策略这个机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。看起来不知道什么意思,实践一下就知道了。
1.随便建两个网页
一个端口是2698,一个2701,按照定义它们是不同源的。

2.用jQuery发起不同源的请求
在2698端口的网页上添加一个按钮,Click事件随便发起两个向端口为2701域的请求。
$("#getOtherDomainThings").click(function () {
$.get("http://localhost:2701/Scripts/jquery-1.4.4.min.js", function (data) {
console.log(data)
})
$.get("http://localhost:2701/home/index", function (data) {
console.log(data)
})
})
根据同源策略,很明显会悲剧了。浏览器会阻止,根本不会发起这个请求。(not allowed by Access-Control-Allow-Origin)
OK,原来jsonp是要解决这个问题的。
script标签的跨域能力
不知道大家知不知道CDN这个东西,例如微软的CDN,使用它,我们的网页可以不提供jQuery,由微软的网站帮我们提供:
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js" type="text/javascript"></script>
回到我们的2698端口的网页,上面我们在Click事件里有一个对2701端口域的jQuery文件的请求,这次使用script标签来请求。
<script type="text/javascript" src="http://localhost:2701/Scripts/jquery-1.4.4.min.js"></script>
当然,200,OK了

同样是端口2698的网页发起对2701域的请求,放在script里设置scr属性的OK了,另一个方式就悲剧。利用script的跨域能力,这就是jsonp的基础。
利用script获取不同源的json
既然它叫jsonp,很明显目的还是json,而且是跨域获取。根据上面的分析,很容易想到:利用js构造一个script标签,把json的url赋给script的scr属性,把这个script插入到dom里,让浏览器去获取。实践:
function CreateScript(src) {
$("<script><//script>").attr("src", src).appendTo("body")
}
添加一个按钮事件来测试一下:
$("#getJsonByHand").click(function () {
CreateScript("http://localhost:2701/home/somejson")
})

首先,第一个浏览器,http://localhost:2701/home/somejson这个Url的确是存在一个json的,而且在2698网页上用script标签来请求这个2701这个Url也是200OK的,但是最下面报js语法错误了。原来用script标签加载完后,会立即把响应当js去执行,很明显{"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"}不是合法的js语句。
利用script获取异域的jsonp
显然,把上面的json放到一个回调方法里是最简单的方法。例如,变成这样:

如果存在jsonpcallback这个方法,那么jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})就是合法的js语句。
由于服务器不知道客户端的回调是什么,不可能hard code成jsonpcallback,所以就带一个QueryString让客户端告诉服务端,回调方法是什么,当然,QueryString的key要遵从服务端的约定,上面的是”callback“。
添加回调函数:
function jsonpcallback(json) {
console.log(json)
}
把前面的方法稍微改改参数:
$("#getJsonpByHand").click(function () {
CreateScript("http://localhost:2701/home/somejsonp?callback=jsonpcallback")
})

200OK,服务器返回jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"}),我们也写了jsonpcallback方法,当然会执行。OK顺利获得了json。没错,到这里就是jsonp的全部。
利用jQuery获取jsonp
上面的方式中,又要插入script标签,又要定义一个回调,略显麻烦,利用jQuery可以直接得到想要的json数据,同样是上面的jsonp:
$("#getJsonpByJquery").click(function () {
$.ajax({
url: 'http://localhost:2701/home/somejsonp',
dataType: "jsonp",
jsonp: "callback",
success: function (data) {
console.log(data)
}
})
})
得到的结果跟上面类似。
总结
一句话就是利用script标签绕过同源策略,获得一个类似这样的数据,jsonpcallback是页面存在的回调方法,参数就是想得到的json。
jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})
到这里不免产生一个疑惑,同源策略是基于安全的原因建立的,发起不同源的请求是被认为不安全的,不可以接受的,但为什么这样绕一个小圈子就可以接受呢?这样就安全了吗?感觉就像洗澡时怕被人看见,把门关上,但侧面的大窗户却是打开的,这样做有意义吗?元芳你怎么看?
ADD 原生js:
<button id="btn">click</button>
<script type="text/javascript">
function $(str){
return document.getElementById(str)
}
function CreateScript(src) {
var Scrip=document.createElement('script');
Scrip.src=src;
document.body.appendChild(Scrip);
}
function jsonpcallback(json) {
console.log(json);//Object { email="中国", email2="中国222"}
}
$('btn').onclick=function(){
CreateScript("http://localhost:51335/somejson?callback=jsonpcallback")
}
</script>
二,案例二
跨域的安全限制都是对浏览器端来说的,服务器端是不存在跨域安全限制的。
浏览器的同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。
如果协议,端口和主机对于两个页面是相同的,则两个页面具有相同的源,否则就是不同源的。
如果要在js里发起跨域请求,则要进行一些特殊处理了。或者,你可以把请求发到自己的服务端,再通过后台代码发起请求,再将数据返回前端。
这里讲下使用jquery的jsonp如何发起跨域请求及其原理。
先看下准备环境:两个端口不一样,构成跨域请求的条件。
获取数据:获取数据的端口为9090

请求数据:请求数据的端口为8080

1、先看下直接发起ajax请求会怎么样
下面是发起请求端的代码:

1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7 $(document).ready(function () {
8
9 $("#btn").click(function () {
10 $.ajax({
11 url: 'http://localhost:9090/student',
12 type: 'GET',
13 success: function (data) {
14 $(text).val(data);
15 }
16 });
17
18 });
19
20 });
21 </script>
22 </head>
23 <body>
24 <input id="btn" type="button" value="跨域获取数据" />
25 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
26 </body>
27 </html>

请求的结果如下图:可以看到跨域请求因为浏览器的同源策略被拦截了。

2、接下来看如何发起跨域请求。解决跨域请求的方式有很多,这里只说一下jquery的jsop方式及其原理。
首先我们需要明白,在页面上直接发起一个跨域的ajax请求是不可以的,但是,在页面上引入不同域上的js脚本却是可以的,就像你可以在自己的页面上使用<img src=""> 标签来随意显示某个域上的图片一样。
比如我在8080端口的页面上请求一个9090端口的图片:可以看到直接通过src跨域请求是可以的。

3、那么看下如何使用<script src="">来完成一个跨域请求:
当点击"跨域获取数据"的按钮时,添加一个<script>标签,用于发起跨域请求;注意看请求地址后面带了一个callback=showData的参数;
showData即是回调函数名称,传到后台,用于包裹数据。数据返回到前端后,就是showData(result)的形式,因为是script脚本,所以自动调用showData函数,而result就是showData的参数。
至此,我们算是跨域把数据请求回来了,但是比较麻烦,需要自己写脚本发起请求,然后写个回调函数处理数据,不是很方便。

1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7 //回调函数
8 function showData (result) {
9 var data = JSON.stringify(result); //json对象转成字符串
10 $("#text").val(data);
11 }
12
13 $(document).ready(function () {
14
15 $("#btn").click(function () {
16 //向头部输入一个脚本,该脚本发起一个跨域请求
17 $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
18 });
19
20 });
21 </script>
22 </head>
23 <body>
24 <input id="btn" type="button" value="跨域获取数据" />
25 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
26
27 </body>
28 </html>

服务端:

1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2 response.setCharacterEncoding("UTF-8");
3 response.setContentType("text/html;charset=UTF-8");
4
5 //数据
6 List<Student> studentList = getStudentList();
7
8
9 JSONArray jsonArray = JSONArray.fromObject(studentList);
10 String result = jsonArray.toString();
11
12 //前端传过来的回调函数名称
13 String callback = request.getParameter("callback");
14 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
15 result = callback + "(" + result + ")";
16
17 response.getWriter().write(result);
18 }

结果:

4、再来看jquery的jsonp方式跨域请求:
服务端代码不变,js代码如下:最简单的方式,只需配置一个dataType:'jsonp',就可以发起一个跨域请求。jsonp指定服务器返回的数据类型为jsonp格式,可以看发起的请求路径,自动带了一个callback=xxx,xxx是jquery随机生成的一个回调函数名称。
这里的success就跟上面的showData一样,如果有success函数则默认success()作为回调函数。

1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 $(document).ready(function () {
9
10 $("#btn").click(function () {
11
12 $.ajax({
13 url: "http://localhost:9090/student",
14 type: "GET",
15 dataType: "jsonp", //指定服务器返回的数据类型
16 success: function (data) {
17 var result = JSON.stringify(data); //json对象转成字符串
18 $("#text").val(result);
19 }
20 });
21
22 });
23
24 });
25 </script>
26 </head>
27 <body>
28 <input id="btn" type="button" value="跨域获取数据" />
29 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
30
31 </body>
32 </html>

效果:

再看看如何指定特定的回调函数:第30行代码
回调函数你可以写到<script>下(默认属于window对象),或者指明写到window对象里,看jquery源码,可以看到jsonp调用回调函数时,是调用的window.callback。
然后看调用结果,发现,请求时带的参数是:callback=showData;调用回调函数的时候,先调用了指定的showData,然后再调用了success。所以,success是返回成功后必定会调用的函数,就看你怎么写了。

1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 function showData (data) {
9 console.info("调用showData");
10
11 var result = JSON.stringify(data);
12 $("#text").val(result);
13 }
14
15 $(document).ready(function () {
16
17 // window.showData = function (data) {
18 // console.info("调用showData");
19 //
20 // var result = JSON.stringify(data);
21 // $("#text").val(result);
22 // }
23
24 $("#btn").click(function () {
25
26 $.ajax({
27 url: "http://localhost:9090/student",
28 type: "GET",
29 dataType: "jsonp", //指定服务器返回的数据类型
30 jsonpCallback: "showData", //指定回调函数名称
31 success: function (data) {
32 console.info("调用success");
33 }
34 });
35 });
36
37 });
38 </script>
39 </head>
40 <body>
41 <input id="btn" type="button" value="跨域获取数据" />
42 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
43
44 </body>
45 </html>

效果图:


再看看如何改变callback这个名称:第23行代码
指定callback这个名称后,后台也需要跟着更改。

1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 function showData (data) {
9 console.info("调用showData");
10
11 var result = JSON.stringify(data);
12 $("#text").val(result);
13 }
14
15 $(document).ready(function () {
16
17 $("#btn").click(function () {
18
19 $.ajax({
20 url: "http://localhost:9090/student",
21 type: "GET",
22 dataType: "jsonp", //指定服务器返回的数据类型
23 jsonp: "theFunction", //指定参数名称
24 jsonpCallback: "showData", //指定回调函数名称
25 success: function (data) {
26 console.info("调用success");
27 }
28 });
29 });
30
31 });
32 </script>
33 </head>
34 <body>
35 <input id="btn" type="button" value="跨域获取数据" />
36 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
37
38 </body>
39 </html>

后台代码:

1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2 response.setCharacterEncoding("UTF-8");
3 response.setContentType("text/html;charset=UTF-8");
4
5 //数据
6 List<Student> studentList = getStudentList();
7
8
9 JSONArray jsonArray = JSONArray.fromObject(studentList);
10 String result = jsonArray.toString();
11
12 //前端传过来的回调函数名称
13 String callback = request.getParameter("theFunction");
14 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
15 result = callback + "(" + result + ")";
16
17 response.getWriter().write(result);
18 }

效果图:

最后看看jsonp是否支持POST方式:ajax请求指定POST方式
可以看到,jsonp方式不支持POST方式跨域请求,就算指定成POST方式,会自动转为GET方式;而后端如果设置成POST方式了,那就请求不了了。
jsonp的实现方式其实就是<script>脚本请求地址的方式一样,只是ajax的jsonp对其做了封装,所以可想而知,jsonp是不支持POST方式的。

1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 $(document).ready(function () {
9
10 $("#btn").click(function () {
11
12 $.ajax({
13 url: "http://localhost:9090/student",
14 type: "POST", //post请求方式
15 dataType: "jsonp",
16 jsonp: "callback",
17 success: function (data) {
18 var result = JSON.stringify(data);
19 $("#text").val(result);
20 }
21 });
22 });
23
24 });
25 </script>
26 </head>
27 <body>
28 <input id="btn" type="button" value="跨域获取数据" />
29 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
30 </body>
31 </html>

效果图:


再补充一点,回到第一条:CORS头缺少“Access-Control-Allow-Origin”。
有时候你会发现其它都没问题,出现这个错误:这个错误代表服务端拒绝跨域访问。如果出现这个错误,就需要在服务端设置允许跨域请求。
response.setHeader("Access-Control-Allow-Origin", "*"); 设置允许任何域名跨域访问

设置可以跨域访问:第6行代码或第8行代码,设置其中一个即可。

1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2 response.setCharacterEncoding("UTF-8");
3 response.setContentType("text/html;charset=UTF-8");
4
5 // * 表示允许任何域名跨域访问
6 response.setHeader("Access-Control-Allow-Origin", "*");
7 // 指定特定域名可以访问
8 response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/");
9
10 //数据
11 List<Student> studentList = getStudentList();
12
13 JSONArray jsonArray = JSONArray.fromObject(studentList);
14 String result = jsonArray.toString();
15
16 //前端传过来的回调函数名称
17 String callback = request.getParameter("callback");
18 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
19 result = callback + "(" + result + ")";
20
21 response.getWriter().write(result);
22 }

总结:jQuery ajax方式以jsonp类型发起跨域请求,其原理跟<script>脚本请求一样,因此使用jsonp时也只能使用GET方式发起跨域请求。跨域请求需要服务端配合,设置callback,才能完成跨域请求。
三:解析
1,现在假设8000,和9000两个端口号,不同的域
一,8000直接访问另一个域9000的js脚本,这种情况好处理,这个js脚本直接拼接成一个 方法.(json格式的数据)这样就行了。
url直接就是var url = "http://localhost:8080/html5/jsonp_data.js";这种的就行了
jsonp.js 就是jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})
添加回调函数:
function jsonpcallback(json) {
console.log(json)
}
把前面的方法稍微改改参数:
$("#getJsonpByHand").click(function () {
CreateScript("http://localhost:2701/home/somejsonp?callback=jsonpcallback")
})
返回之后让回调函数jsonpcallback去解析json格式的对象。
2,现在假设8080,和9090两个端口号,不同的域
假如这个json格式的数据是从数据库中查出来的怎么办。不是放在一个js脚本中的。
这是一个url的请求
$("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
下面的是json格式的数据返回后的解析
function showData (result) {
var data = JSON.stringify(result); //json对象转成字符串
$("#text").val(data);
}
服务器的代码:
//数据
List<Student> studentList = getStudentList();
JSONArray jsonArray = JSONArray.fromObject(studentList);
String result = jsonArray.toString();
//前端传过来的回调函数名称
String callback = request.getParameter("callback");
//用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
result = callback + "(" + result + ")";
response.getWriter().write(result);
3,ajax的解析跨域请求
它有固定的套路的:回调函数的解析
function showData (data) {
console.info("调用showData");
var result = JSON.stringify(data);
$("#text").val(result);
}
$.ajax({
url: "http://localhost:9090/student",
type: "GET",
dataType: "jsonp", //指定服务器返回的数据类型
jsonpCallback: "showData", //指定回调函数名称
success: function (data) {
console.info("调用success");
}
});
服务端的代码不变,
4,ajax的解析跨域请求的另一种写法
$.ajax({
url: "http://localhost:9090/student",
type: "GET",
dataType: "jsonp", //指定服务器返回的数据类型
success: function (data) {
var result = JSON.stringify(data); //json对象转成字符串
$("#text").val(result);
}
});
服务端代码不变,
同时不用写回调函数的解析函数了。
5,ajax的解析跨域请求的小知识点
当制定参数名称的时候,后台的代码也得相应的变化一下了。
function showData (data) {
console.info("调用showData");
var result = JSON.stringify(data);
$("#text").val(result);
}
$(document).ready(function () {
$("#btn").click(function () {
$.ajax({
url: "http://localhost:9090/student",
type: "GET",
dataType: "jsonp", //指定服务器返回的数据类型
jsonp: "theFunction", //指定参数名称
jsonpCallback: "showData", //指定回调函数名称
success: function (data) {
console.info("调用success");
}
});
});
List<Student> studentList = getStudentList();
JSONArray jsonArray = JSONArray.fromObject(studentList);
String result = jsonArray.toString();
//前端传过来的回调函数名称
String callback = request.getParameter("theFunction");
//用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
result = callback + "(" + result + ")";
response.getWriter().write(result);
jsonp的案例的更多相关文章
- jsonp小案例
jsonp详解 例子:
- JSONP跨域访问百度实现搜索提示小案例
一.JSONP简介 JSONP 全称 JSON with padding(填充式 JSON 或参数式 JSON),JSONP实现跨域请求的原理,就是动态创建<script>标签,然后利用& ...
- jsonp全国天气案例
案例1: 1.获取跨域数据 2.将数据按照下面的效果放到body里面 key: f49570d39b02b3c203526b5d8255aa61 079179afb105ce2bae9f5d0 ...
- 跨域解决方案之JSONP,通过借助调用百度搜索的API了解跨域案例
跨域解决方案之JSONP 同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web ...
- 乌云jsonp案例
新浪微博之点击我的链接就登录你的微博(JSONP劫持) 生活处处有惊喜啊!逛逛wooyun都能捡到bug. 测试的时候没关burp,逛乌云的时候抓到一条url: http://login.sina.c ...
- 关于JQuery 中$.ajax函数利用jsonp实现Ajax跨域请求ASP.NET的WebService成功获取数据的案例
部署环境:Window 7 SP1+IIS7 成功方案: 其成功解决问题的几个重要因素如下: 1. 由于WebService默认不支持Get请求,所以要在Web.config配置文件内的& ...
- 案例:1 Ionic Framework+AngularJS+ASP.NET MVC WebApi Jsonp 移动开发
落叶的庭院扫的一干二净之后,还要轻轻把树摇一下,抖落几片叶子,这才是Wabi Sabi的境界. 介绍:Ionic是移动框架,angularjs这就不用说了,ASP.Net MVC WebApi提供数据 ...
- jsonp案例
<button id="btn">click</button><script type="text/javascript"> ...
- cas sso ajax的jsonp实现方案总结(新浪微薄、淘宝案例分析)
Cas自定义登录页面Ajax实现:http://cydiay.iteye.com/blog/1738713 CAS 之 跨域 Ajax 登录实践:http://denger.iteye.com/blo ...
随机推荐
- EasyUI实现更换主题能过样式添加id实现
EasyUI实现更换主题能过样式添加id实现,将原来的样式值添加到cookie中保存,这样下次浏览器访问时,就是我们原来选择的样式! 首先将easyui的样式文件加入一个ID,这里命名为easyuiT ...
- ACE在windows下的编译及配置(VS2010)
ACE在windows下的编译及配置(VS2010) 分类: -[小西南]- 2013-08-06 16:17 2354人阅读 评论( ...
- [Python Study Notes] 编程仪式感的Hello World!
学习还是要有一点仪式感的,学单片机第一步,点个灯:学编程第一步,hello world! C:\Users\Liu>python Python 3.6.4 (v3.6.4:d48eceb, De ...
- Oracle,Sql,procedure 感觉自己写的很棒的一个存储过程
感觉自己写的很棒的一个Oracle存储过程,(其实想说很叼^,^). 集成了一堆操作数据的功能(至少几十), 包括存储过程执行异常信息输出帮助诊断. 亮点很多, 比如`over(partition b ...
- 置换群、Burnside引理与等价类计数问题
置换群.Burnside引理与等价类计数问题 标签: 置换群 Burnside引理 置换 说说我对置换的理解,其实就是把一个排列变成另外一个排列.简单来说就是一一映射.而置换群就是置换的集合. 比如\ ...
- 论 Java 中的内存分配
Java内存分配主要包括以下几个区域: 1. 寄存器:我们在程序中无法控制 2. 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 3. 堆:存放用new产生的数据 4. 静 ...
- keras初涉笔记【一】
安装keras依赖的库 sudo pip install numpy sudo pip install scipy sudo pip installl pyyaml sudo pipi install ...
- git命令 高级
Git 分支 - 分支的删除 git删除本地分支 git branch -D br git删除远程分支 git push origin :br (origin 后面有空格) clone服务器上的资源 ...
- CentOS下安装配置cmake
安装环境:CentOS-6.4 安装方式:源码编译安装 软件:cmake-2.8.5.tar.gz 下载地址暂时不提供,去百度搜一下准有 安装前提 系统中已经安装了gcc. ncurses-de ...
- Angular:利用内容投射向组件输入ngForOf模板
现在,我们写一个组件puppiesListCmp,用于显示小狗狗的列表: //puppies-list.component.ts @Component({ selector: 'puppies-lis ...
