使用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":"[email protected]","Remark":"我来自遥远的东方"}不是合法的js语句。

利用script获取异域的jsonp

显然,把上面的json放到一个回调方法里是最简单的方法。例如,变成这样:

如果存在jsonpcallback这个方法,那么jsonpcallback({"Email":"[email protected]","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":"[email protected]","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":"[email protected]","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/

时间: 2024-10-23 16:34:34

使用Jsonp实现跨域请求的相关文章

Vue中使用jsonp进行跨域请求

Vue-resouse中可以通过this.$http.jsonp的方式直接使用jsonp进行跨域请求.官方在推荐使用axios之后,axios并没有集成jsonp.但在axios的github中(https://github.com/mzabriskie/axios/blob/master/COOKBOOK.md#jsonp),可以直接安装jsonp并使用他来坐跨域请求. <script> var jsonp = require('jsonp'); export default { data(

PHP AJAX JSONP实现跨域请求使用实例

在之前我写过“php返回json数据简单实例”,“php返回json数据中文显示的问题”和“在PHP语言中使用JSON和将json还原成数组”.有兴趣的童鞋可以看看 今天我写的是PHP AJAX JSONP使用的实例.不清楚jsonp是什么的请自己搜索 实例1 test.html <!doctype html> <html> <head> <meta charset="utf-8"> <title>test</title

Nginx反向代理、CORS、JSONP等跨域请求解决方法总结

由于 Javascript 同源策略的存在使得一个源中加载来自其它源中资源的行为受到了限制.即会出现跨域请求禁止. 通俗一点说就是如果存在协议.域名.端口或者子域名不同服务端,或一者为IP地址,一者为域名地址(在跨域问题上,域仅仅是通过“ url的首部 ”来识别而不会去尝试判断相同的IP地址对应着两个域或者两个域是否同属同一个IP),之中任意服务端旗下的客户端发起请求其它服务端资源的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源. 但很多时候我们却又不得不

用JSONP方式跨域请求

JQUERY 中封装的JSONP请求方法 1.index.html 中的javascript $(function(){ $.ajax({   type: "GET",   async:false,   url: "http://www.vm.com:81/index.php", //跨域请求的地址   data:{'birt':2016},   dataType: 'jsonp',   jsonp: 'jsoncallback',   success: funct

mvc中使用jsonp进行跨域请求详细说明

在web开发中,如果你要在不同域下进行数据异步请求,会出现一个No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”的错误提示.该提示信息说明,跨域请求是违反了“同源策略”的.但是在开发中又难免会遇到跨域请求的需求,所以前辈们也是留下了跨域请求数据的方法jsonp跨域请求. 我们以最为典型的Jquery做例子,后台用的asp.net mvc.我们先构造一个action的返回对象,用于返回json

利用jsonp实现跨域请求

同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行.如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问. 由于同源策略,我们在使用ajax请求资源时不能跨域请求,也就是说必须是同一个域名,协议,端口.

来说说SpringMVC + JSONP的跨域请求

先来说说场景,JSON,这货大家应该都懂,不懂的请自动面壁思过,那么什么是JSONP,不是JSON放了个P就叫JSONP,而是JSON with Padding,在进行跨域请求的时候需要的数据,什么是跨域,打个比方:在user.weixin.com下的某个页面下,用户服务需要调用订单服务,请求order.weixin.com,那么在这两个二级域名下,请求是互斥的,如果请求就会报错. 先来看看本域下的请求,同域名下是可以获取到json数据的 那么如果换一个域名呢?可以看到请求被拒绝了,说到底这还是

不用jsonp实现跨域请求

这几天要用到跨域请求,我在网上找了好多资料,最后自己研究出来一个比较简单方便的, 请求的过程和jquery普通的ajax一样.我用的是.net平台 ,IIS7.5 来看一下后台的代码,我是用MVC的Controll做数据接口. 接下来是前台代码了: <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitio

ajax jsonp的跨域请求

1.页面ajax的请求 $.ajax({ async: false, url: 'http://localhost:8080/downloadVideos',//跨域的dns/document!searchJSONResult.action, type: "GET", dataType: 'jsonp', jsonp: 'jsoncallback', jsonpCallback: "cb",//自定义返回函数的名称,要与服务端保持一致 data: { id:ID,