Jsonp解决ajax跨域问题

转载 2016年05月31日 11:21:19
<pre name="code" class="javascript">alert("this is other(8888) js");


<pre name="code" class="java"><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
    function jsonp_fun(){
        $.ajax({
            url:'http://localhost:8888/other/index.jsp',
            type:'post',
            dataType:'text',
            success:function(data){
                console.log(data);
            }
        });
    }
</script>
</head>
<body>
    <input type="button" value="jsonp" onclick="jsonp_fun()"/>
</body>
</html>



other(8888)项目中index.jsp如下:// 因为jsp实际就是servlet,这里就用jsp代替servlet演示。

<pre name="code" class="java"><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
</head>
<body>
    other domain
</body>
</html>



其实中上面看无非就是jsonp页面中点击按钮ajax去获取other页面中的数据。

结果如下:chrome控制台

这里写图片描述

XMLHttpRequest cannot load http://localhost:8888/other/index.jsp. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed

以上提示就是指跨域问题,不能从8080这个域去访问8888域的资源。

2、利用script标签去访问other域的js文件

由于<script>标签的src是支持跨域请求的。最常见的就是CDN服务的应用啦,比如我项目中,如果想用jQuery,但是就没有这个js文件,去下载要找很久,而且版本还不知道下的对不对,那么可以百度搜jquery cdn,我随便找一个,比如bootstrap的cdn:http://www.bootcdn.cn/jquery/,有很多版本供你选择,只要在项目中加上就行了,最大缺点的话就是你没网的话,就引入不到啦。

  • 2.1 在other根路径创建js/other.js文件,内容如下:
alert("this is other(8888) js");

  • 2.2 在jsonp/index.jsp中,加入script标签,引入other的js
<script type="text/javascript" src="http://localhost:8888/other/js/other.js"></script>

进入http://localhost:8080/jsonp/index.jsp,会立马弹出alert,表示引入的js文件自动执行了,跨域请求js成功。

这里写图片描述

  • 2.3 同样的,直接引用,会立马执行立马的alert,那么在other.js中写函数,同样jsonp/index.jsp中也能调用到,这点就不演示了,项目开发中大多都是这样做的,页面与js/css分离。

  • 2.4 另外说明一点,如果在other.js中有函数通过ajax调用8080中的东西,然后引入之后,调用这个函数,也是可以的,但是如果other.js中函数ajax调用8888的东西,引入之后,调用这个函数,同样是跨域的。

3、script实现跨域请求

  • 3.1 简单模拟服务器返回数据

将jsonp/index.jsp改成如下:这里注意引入的other.js的位置,是在函数getResult之后的,如果在它之前的话,会提示函数不存在。js加载顺序是从上开始,在之前调用没创建的,不能成功。注意这里是指引入的js文件,如果是同一个js文件或者当前页面的js中,先执行调用,然后再写函数也是没有问题的,但是如果先执行调用引入js文件中的函数,然后再引入js文件,就会提示函数不存在。

<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
    function jsonp_fun(){
        $.ajax({
            url:'http://localhost:8888/other/index.jsp',
            type:'post',
            dataType:'text',
            success:function(data){
                console.log(data);
            }
        });
    }

    function getResult(data){
        alert(data.result);
    }
</script>
<script type="text/javascript" src="http://localhost:8888/other/js/other.js"></script>

然后other.js

getResult({"result":"this is other domain's data"});

也就是在jsonp/index.jsp页面写好函数,然后引入其他域的js传入参数去调用这个函数,这里的参数你可以先看做是其他域服务器的接口返回的数据。

刷新页面,效果当然是

弹出alert框,this is other domain's data
  • 3.2 模拟接口访问 
    看到这里,你会不会还是想不懂,上面js弄啥的,传个死的数据,有什么实际意义吗?,其实script的src不仅可以接js的地址,还可以接servlet的地址,也就是http接口地址,所以接下来,懒得写servlet,这里还是写jsp当做接口,在other项目中新建other.jsp页面,内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
    String params = request.getParameter("params");
    out.println("ajax cross success,the server receive params :"+params);
%>

内容很简单,也就是接受一个params的参数,然后返回数据给调用者。

我们在jsonp/index.jsp中加上

<script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp"></script>

看到这个地址,你是不是很熟悉,不熟悉的证明你用servlet用蠢了,jsp也是servlet,流程就是页面一加载的时候,script标签就会去发送请求,然后返回数据。那么我们刷新页面,看看效果。

这里写图片描述

<code class="language-console hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Uncaught <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">SyntaxError</span>: Unexpected identifier</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

报错了,如上,然后代码有问题?No,点击错误,你会看到请求的东西也打印出来了,就是提示错误,表示这个东西浏览器不认识,其实是script不认识啦。

这里写图片描述

还不明白,那么你去页面加上如下内容,你看报不报错!!肯定报错

<script type="text/javascript">
    ajax cross success,the server receive params : jsonp_param
</script>

那么js不能解析,我们换一种思路,要是我们输出的是JSON字符串或者调用当前页面函数的字符串了,类似于3.1中返回的 
getResult({“result”:”this is other domain’s data”});

所以改造一下,把other.jsp中的内容改成

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
    String params = request.getParameter("params");
    //out.println("ajax cross success,the server receive params :"+params);
    out.println("getResult({'result':'"+params+"'})");
%>
别忘了,之前jsonp/index.jsp中我们定义了,那么加入引用之后,依然记得getResult函数与引入函数的先后顺序问题。

<script type="text/javascript">
    function getResult(data){
        alert(data.result);
    }
</script>
<script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp"></script>

刷新页面,发现大工告成。

这里写图片描述

至此,大部分原理已经讲完了,还有一个问题,这里服务器返回的是getResult(xxx),其中这里的xxx可以当做是经过接口的很多处理,然后塞进去的值,但是这个getResult这个函数名,调用方与其他域服务器这一方怎么约定这个名字是一致的了,况且很多公司自己做服务的,别的公司的开发人员去调用,难道每个人都去那么公司去约定调用函数的名字?怎么可能,所以有人就想出来了一种解决方案,当然不是我~~,其实也很简单啦,也就是把回调的函数名字也一起传过去不就行了,所以代码如下:

<script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp&callback=getResult"></script>
other.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
    String params = request.getParameter("params");
    String callback = request.getParameter("callback");
    // 经过该接口一系列操作,然后得到data,将data返回给调用者
    String data = "{'result':'"+params+"'}";
    out.println(callback + "("+data+")");
%>
代码很简单,也就是传递一个回调函数的参数名,然后经过该接口一系列操作,将返回数据,塞到回调函数里面,调用端的函数就得到了该接口的数据,也就是类似于ajax中succsss:function(data),然后处理data一样,这里的success回调函数,相当于上面的getResult函数。当然你也可以写的优雅一点,比如:
function CreateScript(src) {
        $("<script><//script>").attr("src", src).appendTo("body")
    }

    function jsonp_fun(){
         CreateScript("http://localhost:8888/other/other.jsp?params=fromjsonp&callback=getResult")
    }

4、Jquery的JSONP

至此跨域请求的原理已经讲清楚了,但是仍然还有一个问题,总觉得这样用有点怪是不是,如果用jquery的话,调用就很简单了,其实jquery底层实现也是拼了一个script,然后指定src这种方式,跟上面讲的一样,只是jquery封装了一下,显得更加优雅,跟ajax调用方式差不多,所以容易记,代码如下:

<script type="text/javascript">
    function getResult(data){
        alert("through jsonp,receive data from other domain : "+data.result);
    }

    function jsonp_fun(){
        $.ajax({
            url:'http://localhost:8888/other/other.jsp',
            type:'post',
            data:{'params':'fromjsonp'},
            dataType: "jsonp",
            jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
            jsonpCallback:"getResult",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以不写这个参数,jQuery会自动为你处理数据
            success: function(data){
            },
            error: function(){
                alert('fail');
            }
        });
    }
</script>
<body>
    <input type="button" value="jsonp" onclick="jsonp_fun()"/>
</body>

这里的jsonCallback,回调函数设置为getResult,那么返回后会先调用getResult函数中的代码,再调用success函数中的代码,一般情况下,不用定义getResult函数,同样jsonCallback不需要设置,那么就只执行success中的代码,也就跟平时的ajax一样用啦。

所以实际工作用法如下:

function jsonp_fun(){
        $.ajax({
            url:'http://localhost:8888/other/other.jsp',
            type:'post',
            data:{'params':'fromjsonp'},
            dataType: "jsonp",
            jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
            success: function(data){
                alert("through jsonp,receive data from other domain : "+data.result);
            },
            error: function(){
                alert('fail');
            }
        });
    }

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
    String params = request.getParameter("params");
    String callback = request.getParameter("callback");
    // 经过该接口一系列操作,然后得到data,将data返回给调用者
    String data = "{\"result\":\""+params+"\"}";
    out.println(callback + "("+data+")");
%> 

这里没有指定jsonpCallback,实际上jquery底层拼装了一个函数名,当然生成函数规则就没研究了。

这里写图片描述

补充:

  • 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提供公开服务。


文章来源:http://blog.csdn.net/saytime/article/details/51540876





XMLHttpRequest的同域请求和跨域请求以及jsonp

XMLHttpRequest的同域请求和跨域请求以及jsonpXMLHttpRequest的同域请求和跨域请求以及jsonp 使用XMLHttpRequest xhr同域请求get post xhr跨...
  • ali1995
  • ali1995
  • 2016年12月14日 11:12
  • 6498

深入理解Ajax结合JSONP实现跨域请求

深入理解Ajax结合JSONP实现跨域请求
  • canot
  • canot
  • 2016年03月02日 09:34
  • 3974

XMLHttpRequest VS. JSONP

当我们利用XMLHttpRequest对象从本地服务器获取数据时是可以的。     假设我们使用的数据格式为JSON(JavaScript Object Notation),并且我们在本地服务器上部...
  • czjuttsw
  • czjuttsw
  • 2013年02月27日 21:54
  • 2472

跨域请求 数据返回却无法执行回调函数的原因之一

由于公司项目的问题,导致跨域的情况比较多。既要考虑安全性问题又要解决跨域。只能从中做一些取舍。今天发现的问题是,前端已经获取了后台返回的CALLBACK函数,但是无论如何都不执行。这可把我急的,之前也...
  • a250758092
  • a250758092
  • 2017年04月13日 23:12
  • 1071

jsonp跨域中后台返回的不是回调函数形式

在常用的jsonp跨域请求时后台返回的是一个回调函数,然而当后台传的不是以函数形式返回的,实际返回的是一个变量,那么原生js封装的jsonp就不能使用了,那么我们该如何拿到后台传过来的数据呢?其实原理...
  • xlei1123
  • xlei1123
  • 2016年06月20日 17:09
  • 2456

JSONP实现Ajax跨域访问-强哥

JSONP实现Ajax跨域访问JSONP = JSON with padding,但JSONP和JSON不一样,它并不是一种数据格式。JSONP是一种JavaScript实现跨域cross-domai...
  • u011886490
  • u011886490
  • 2013年08月30日 14:39
  • 548

使用JSONP进行跨域的数据传递

使用JSONP进行跨域的数据传递     先说说浏览器的“同源策略(SOP:Same Origin Policy)”,简单的说,就是浏览器限制脚本程序只能和同协议、同域名、同端口的脚本进行交互(共享...
  • Zhongxiucheng
  • Zhongxiucheng
  • 2012年05月28日 16:25
  • 1392

jsonp跨域学习总结

一、背景: Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如标签script、img、iframe)二、原理 JSONP,...
  • Dorothy1224
  • Dorothy1224
  • 2017年09月13日 14:35
  • 85

1.1 vue2.0jsonp获取数据

jsonp介绍1.原理: 1.写js的时候,我们会在script标签里面引入我们需要的js文件,有自己网站上的,也有别的网站上的,不管哪个网站上的js文件,只要引入了,都可以去运行,丝毫不受同源策略的...
  • lvlemo
  • lvlemo
  • 2017年09月29日 15:40
  • 250

Jsonp解决ajax跨域问题

一、介绍 最近跨域问题比较多,而且自己刚好也看到这一块,就总结了一下,关于JSONP的东西百度的话东西确实很多,很多人都是复制别人的,如此下去,其实找的资料就那么几份,关键是我还看不懂,可能是能力...
  • saytime
  • saytime
  • 2016年05月30日 22:36
  • 18405
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Jsonp解决ajax跨域问题
举报原因:
原因补充:

(最多只允许输入30个字)