首頁  >  文章  >  web前端  >  Jsonp怎麼能解決ajax跨域

Jsonp怎麼能解決ajax跨域

php中世界最好的语言
php中世界最好的语言原創
2018-04-25 16:42:421451瀏覽

這次帶給大家Jsonp怎麼能解決ajax跨域,Jsonp解決ajax跨域的注意事項有哪些,下面就是實戰案例,一起來看一下。

一、介紹

最近跨域問題比較多,而且自己剛好也看到這一塊,就總結了一下,關於JSONP的東西百度的話東西確實很多,很多人都是複製別人的,如此下去,其實找的資料就那麼幾份,關鍵是我還看不懂,可能是能力問題吧,自己經過很多嘗試,所以總結了一下,終究還是弄懂了皮毛。注意一點是,這裡是用Jsonp解決ajax的跨域問題,具體的實作其實不是ajax。

1、同源策略

瀏覽器有一個很重要的概念-同源策略(Same-Origin Policy)。所謂同源是指,域名,協議,端口相同。不同源的客戶端腳本(JavaScript、ActionScript)在沒明確授權的情況下,不能讀寫對方的資源。

2、JSONP

JSONP(JSON with Padding)是JSON的一種”使用模式”,可用於解決主流瀏覽器的跨域資料存取的問題。由於同源策略,一般來說位於 server1.example.com 的網頁無法與不是 server1.example.com的伺服器溝通,而 HTML 的script 元素是例外。利用 <script> 元素的這個開放策略,網頁可以得到從其他來源動態產生的 JSON 資料,而這個使用模式就是所謂的 JSONP。用 JSONP 抓到的資料不是 JSON,而是任意的JavaScript,用 JavaScript 直譯器執行而不是用 JSON 解析器解析。 </script>

二、實作

1、模擬跨域請求

在本機弄兩個tomcat,端口分別為8080,8888,也就滿足了非同源的條件,那麼要是從一個端口發送ajax去獲取另外一個端口的數據,那麼肯定會報跨域請求問題。

Jsonp怎麼能解決ajax跨域

這裡有兩個項目,分別是jsonp(8080),other(8888),在jsonp專案中index.jsp如下:

nbsp;html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">


<title>Insert title here</title>
<script></script>
<script>
function jsonp_fun(){
$.ajax({
url:&#39;http://localhost:8888/other/index.jsp&#39;,
type:&#39;post&#39;,
dataType:&#39;text&#39;,
success:function(data){
console.log(data);
}
});
}
</script>


<input>

other (8888)專案中index.jsp如下:// 因為jsp其實就是servlet,這裡就用jsp取代servlet示範。

nbsp;html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">


<title>Insert title here</title>
<script></script>


other domain

其實中上面看無非就是jsonp頁面中點選按鈕ajax去取得other頁面中的資料。

結果如下:chrome控制台

Jsonp怎麼能解決ajax跨域

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 access.

#以上提示就是指跨域問題,不能從8080這個域去訪問8888域的資源。

2、利用script標籤去存取other域的js檔案

由於<script>標籤的src是支援跨域請求的。最常見的就是CDN服務的應用程式啦,像是我專案中,如果想用jQuery,但是就沒有這個js文件,去下載要找很久,而且版本還不知道下的對不對,那麼可以百度搜jquery cdn,我隨便找一個,例如bootstrap的cdn:http://www.bootcdn.cn/jquery/,有很多版本供你選擇,只要在項目中加上就行了,最大缺點的話就是你沒網的話,就引入不到啦。 </script>

2.1 在other根路徑建立js/other.js文件,內容如下:

alert("this is other(8888) js");

2.2 在jsonp/index.jsp中,加入script標籤,引入other的js

<script></script>

進入http://localhost:8080/jsonp/index.jsp,會立刻彈出alert,表示引入的js檔案自動執行了,跨域請求js成功。

Jsonp怎麼能解決ajax跨域

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></script>
<script>
function jsonp_fun(){
$.ajax({
url:&#39;http://localhost:8888/other/index.jsp&#39;,
type:&#39;post&#39;,
dataType:&#39;text&#39;,
success:function(data){
console.log(data);
}
});
}
function getResult(data){
alert(data.result);
}
</script>
<script></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页面,内容如下:


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

我们在jsonp/index.jsp中加上

<script></script>

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

Jsonp怎麼能解決ajax跨域

Uncaught SyntaxError: Unexpected identifier

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

Jsonp怎麼能解決ajax跨域

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

<script>
ajax cross success,the server receive params : jsonp_param
</script>

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

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


别忘了,之前jsonp/index.jsp中我们定义了,那么加入引用之后,依然记得getResult函数与引入函数的先后顺序问题。

<script>
function getResult(data){
alert(data.result);
}
</script>
<script></script>

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

Jsonp怎麼能解決ajax跨域

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

<script></script>

other.jsp


代码很简单,也就是传递一个回调函数的参数名,然后经过该接口一系列操作,将返回数据,塞到回调函数里面,调用端的函数就得到了该接口的数据,也就是类似于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")
}</script>

4、Jquery的JSONP

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

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

<input>

这里的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');
}
});
}

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

Jsonp怎麼能解決ajax跨域

补充:

1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。</script>

3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

不使用插件让Ajax实现异步刷新

ajax请求操作返回数据顺序

以上是Jsonp怎麼能解決ajax跨域的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn