使用Jsonp实现跨域请求
来自百度百科的一段话:
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
来自民间的比喻:
JSON(JavaScript Object Notation)和JSONP(JSON with Padding)虽然只有一个字母的差别,但其实他们根本不是一回事儿:JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。我们拿最近比较火的谍战片来打个比方,JSON是地下党们用来书写和交换情报的“暗号”,而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")
}
添加一个按钮事件来测试一下:
$("#getOtherDomainJson").click(function () {
$.get('http://localhost:2701/home/somejson', function (data) {
console.log(data)
})
})
首先,第一个浏览器,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)
}
})
})
附上一段服务端的代码,使用java语言
response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = null;
try {
out = response.getWriter();
String jsonPData = callback + "(" + JSONObject.toJSON("封装的json数据") + ")";
out.print(jsonPData);
} catch (IOException e) {
logger.error("response.getWriter() error",e);
}finally {
if(out != null){
out.flush();
out.close();
}
}
是不是有点奇怪?为什么我没有写回调这个函数呢?而且竟然也运行成功了!哈哈,这就是jQuery的功劳了,jquery在处理jsonp类型的ajax时(还是忍不住吐槽,虽然jquery也把jsonp归入了ajax,但其实它们真的不是一回事儿),自动帮你生成回调函数并把数据取出来供success属性方法来调用,是不是很爽呀?
总结
一句话就是利用script标签绕过同源策略,获得一个类似这样的数据,jsonpcallback是页面存在的回调方法,参数就是想得到的json。
jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})
1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;
2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。
3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。
4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。
总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变这一点!
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>
参考文档:
http://www.cnblogs.com/lemontea/archive/2012/12/11/2812268.html
http://kb.cnblogs.com/page/139725/
使用Jsonp实现跨域请求的更多相关文章
- 关于使用Jsonp做跨域请求
今天在使用Jsonp做跨域请求的练习时碰上这样一个问题 代码如下 <!DOCTYPE html> <html> <head> <meta charset=&q ...
- 使用jsonp进行跨域请求
使用jsonp进行跨域请求 在实际的业务中很多时候需要用到跨域请求,然而jsonp为我们提供了一种非常方便的跨域请求的方式,具体实现代码如下: $.ajax({ type:"get" ...
- 利用JSONP实现跨域请求
前言:有时候一忙起来就没了时间观念,原来我已经有十多天没写博客了.一直想做跨域方面的尝试,无奈最近准备校招没时间动动手.今天就先讲讲JSONP吧,昨晚还在研究QQ空间日志里面网络图片的问题呢,我发现日 ...
- 来说说SpringMVC + JSONP的跨域请求
先来说说场景,JSON,这货大家应该都懂,不懂的请自动面壁思过,那么什么是JSONP,不是JSON放了个P就叫JSONP,而是JSON with Padding,在进行跨域请求的时候需要的数据,什么是 ...
- mvc中使用jsonp进行跨域请求详细说明
在web开发中,如果你要在不同域下进行数据异步请求,会出现一个No ‘Access-Control-Allow-Origin’ header is present on the requested r ...
- Nginx反向代理、CORS、JSONP等跨域请求解决方法总结
由于 Javascript 同源策略的存在使得一个源中加载来自其它源中资源的行为受到了限制.即会出现跨域请求禁止. 通俗一点说就是如果存在协议.域名.端口或者子域名不同服务端,或一者为IP地址,一者为 ...
- 通过 JSONP 实现跨域请求
优质参考资料:https://www.cnblogs.com/chiangchou/p/jsonp.html https://blog.csdn.net/hansexploration/article ...
- jsonp原理,跨域请求头处理
一.jsonp(解决跨域)思路介绍: 因浏览器的同源策略不会拦截link标签内的src请求,所以利用这一点,我们把后端开放的接口路径放在src内, 其在发送请求后会自动接收返回的东西,所以我们可以给要 ...
- CORS和jsonp实现跨域请求
同源策略:所谓同源是指,域名,协议,端口相同,它是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器都会使用这个策略.当浏览器同时打开两个tab页面(两个不同服务器 ...
- 不用jsonp实现跨域请求
这几天要用到跨域请求,我在网上找了好多资料,最后自己研究出来一个比较简单方便的, 请求的过程和jquery普通的ajax一样.我用的是.net平台 ,IIS7.5 来看一下后台的代码,我是用MVC的C ...
随机推荐
- 【leetcode刷题笔记】Median of Two Sorted Arrays
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted ...
- Squid 访问控制配置
Squid 访问控制配置 主配置文件内加入限制参数 vim /etc/squid/squid.conf # 访问控制 acl http proto HTTP # 限制访问 good_domain添加两 ...
- AngularJs 的一则错误 [$INJECTOR:MODULERR]
Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to: Error: [$injector:modu ...
- c++ 关键字extern(声明)和定义的区别
extern : extern int i; // declares but does not define i int i; //declares and defines i ...
- Spring-data-jpa常用方法
- MongoDB快速入门(六)- 更新文档
更新文档 MongoDB的update()和save()方法用于更新文档到一个集合. update()方法将现有的文档中的值更新,而save()方法使用传递到save()方法的文档替换现有的文档. M ...
- DOCKER 简单操作
docker ps -a 列出所有镜像 docker start docder_name dcoker start docker_id 运行某个镜像 docker restart docker_nam ...
- Linux mysql主从同步配置
一.在两台Ubuntu机器上安装mysql1.检查系统中是否安装了mysql 这个是已经安装了的 没有安装的话执行上条命令===============================MySQL的一些 ...
- VCFtools
The C++ executable module examples This page provides usage examples for the executable module. Exte ...
- HRBUST 1717 字典树模板
之前写字典树虽然很熟也能变化 但是一直是到了场上再乱写 写的很长 于是准备写个短点的板子 于是选了个水题 然而写出了1W个bug insert和query反而写的没什么问题.. L c[100050] ...