什麼是域,簡單來說就是協定 網域名稱或位址 連接埠,3者只要有任何一個不同就表示不在同一個網域。跨域,就是在一個域中存取另一個域的資料。
如果只是載入另一個網域的內容,而不需要存取其中的資料的話,跨域是很簡單的,例如使用iframe。但如果需要從另一個網域載入並使用這些資料的話,就會比較麻煩。為了安全性,瀏覽器對這種情況有嚴格的限制,需要在客戶端和服務端同時做一些設定才能實現跨網域請求。
JSONP簡介
JSONP(JSON with Padding)是一種常用的跨域手段,但只支援JS腳本和JSON格式的資料。顧名思義,JSONP是利用JSON作為墊片,從而實現跨域請求的一種技術手段。其基本原理是利用HTML的<script></script>標籤天生可以跨域這一特點,用其加載另一個域的JSON數據,加載完成後會自動運行一個回調函數通知調用者。此過程需要另一個域的服務端支持,所以這種方式實現的跨域並不是任意的。
JQuery對JSONP的支援
JQuery的Ajax物件支援JSONP方式的跨域請求,方法是將crossDomain參數指定為true並且將dataType參數指定為jsonp[1],或使用簡寫形式:getJSON()方法[2]。例如:
// 设置crossDomain和dataType参数以使用JSONP $.ajax({ dataType: "jsonp", url: "http://www.example.com/xxx", crossDomain: true, data: { } }).done(function() { // 请求完成时的处理函数 }); // 使用getJSON $.getJSON("http://www.example.com/xxx?jsoncallback=?", { // 参数 }, function() { // 请求完成时的处理函数 });
使用getJSON時,需要在參數中指定jsoncallback=?,這個就是前面所說的回呼函數,JQuery會自動以一個隨機產生的值(回呼函數名)來取代該參數中的問號部分,從而形成jsoncallback=jQueryxxxxxxx這種形式的參數,然後和其他參數一起使用GET方式發出請求。
使用第一種方式時,只要將dataType參數的值指定為jsonp,JQuery就會自動在請求位址後面加上jsoncallback參數,因此無需手動新增。
JQuery跨域請求的缺陷:錯誤處理
跨網域請求可能會失敗,例如對方伺服器的安全設定拒絕接受來自我方的請求(我方不在對方的信任清單中),或網路不通,或對方伺服器已關閉,或要求位址或參數不正確導致伺服器報錯等等。
在JQuery中,當使用ajax或getJSON發送請求後會回傳一個jqXHR物件[3]。該物件實作了Promise協議,所以我們可以使用它的done、fail、always等介面來處理回呼。例如我們可以用在它的fail回呼中進行請求失敗時的錯誤處理:
var xhr = $.getJSON(...); xhr.fail(function(jqXHR, textStatus, ex) { alert('request failed, cause: ' + ex.message); });
这种方式能够处理“正常的错误”,例如超时、请求被中止、JSON解析出错等等。但它对那些“非正常的错误”,例如网络不通、服务器已关闭等情况的支持并不好。
例如当对方服务器无法正常访问时,在Chrome下你会在控制台看到一条错误信息:
JQuery不会处理该错误,而是选择“静静地失败”:fail回调不会执行,你的代码也不会得到任何反馈,所以你没有处理这种错误的机会,也无法向用户报告错误。
一个例外是在IE8。在IE8中,当网络无法访问时,<script></script>标签一样会返回加载成功的信息,所以JQuery无法根据<script>标签的状态来判断是否已成功加载,但它发现<script>标签“加载成功”后回调函数却没有执行,所以JQuery以此判断这是一个“解析错误”(回调代码没有执行,很可能是返回的数据不对导致没有执行或执行失败),因此返回的错误信息将是“xxxx was not called”,其中的xxxx为回调函数的名称。</script>
也就是说,由于IE8(IE7也一样)的这种奇葩特性,导致在发生网络不通等“非正常错误”时,JQuery反而无法选择“静默失败”策略,于是我们可以由此受益,得到了处理错误的机会。例如在这种情况下,上面的例子将会弹出“xxxx was not called”的对话框。
解决方案
当遇到“非正常错误”时,除了IE7、8以外,JQuery的JSONP在较新的浏览器中全部会“静默失败”。但很多时候我们希望能够捕获和处理这种错误。
实际上在这些浏览器中,<script>标签在遇到这些错误时会触发error事件。例如如果是我们自己来实现JSONP的话可以这样:</script>
var ele = document.createElement('script'); ele.type = "text/javascript"; ele.src = '...'; ele.onerror = function() { alert('error'); }; ele.onload = function() { alert('load'); }; document.body.appendChild(ele);
在新浏览器中,当发生错误时将会触发error事件,从而执行onerror回调弹出alert对话框:
但是麻烦在于,JQuery不会把这个<script></script>标签暴露给我们,所以我们没有机会为其添加onerror事件处理器。
下面是JQuery实现JSONP的主要代码:
jQuery.ajaxTransport( "script", function(s) { if ( s.crossDomain ) { var script, head = document.head || jQuery("head")[0] || document.documentElement; return { send: function( _, callback ) { script = document.createElement("script"); script.async = true; ... script.src = s.url; script.onload = script.onreadystatechange = ...; head.insertBefore( script, head.firstChild ); }, abort: function() { ... } }; } });
可以看到script是一个局部变量,从外部无法获取到。
那有没有解决办法呢?当然有:
- 自己实现JSONP,不使用JQuery提供的
- 修改JQuery源码(前提是你不是使用的CDN方式引用的JQuery)
- 使用本文介绍的技巧
前两种不说了,如果愿意大可以选择。下面介绍另一种技巧。
通过以上源码可以发现,JQuery虽然没有暴露出script变量,但是它却“暴露”出了<script>标签的位置。通过send方法的最后一句:</script>
head.insertBefore( script, head.firstChild );
可以知道这个动态创建的新创建标签被添加为head的第一个元素。而我们反其道而行之,只要能获得这个head元素,不就可以获得这个script了吗?head是什么呢?继续看源码,看head是怎么来的:
head = document.head || jQuery("head")[0] || document.documentElement;
原来如此,我们也用同样的方法获取就可以了,所以补全前面的那个例子,如下:
var xhr = $.getJSON(...); // for "normal error" and ie 7, 8 xhr.fail(function(jqXHR, textStatus, ex) { alert('request failed, cause: ' + ex.message); }); // for 'abnormal error' in other browsers var head = document.head || $('head')[0] || document.documentElement; // code from jquery var script = $(head).find('script')[0]; script.onerror(function(evt) { alert('error'); });
这样我们就可以在所有浏览器(严格来说是绝大部分,因为我没有测试全部浏览器)里捕获到“非正常错误”了。
这样捕获错误还有一个好处:在IE7、8之外的其他浏览器中,当发生网络不通等问题时,JQuery除了会静默失败,它还会留下一堆垃圾不去清理,即新创建的<script>标签和全局回调函数。虽然留在那也没什么大的危害,但如果能够顺手将其清理掉不是更好吗?所以我们可以这样实现onerror:</script>
// handle error alert('error'); // do some clean // delete script node if (script.parentNode) { script.parentNode.removeChild(script); } // delete jsonCallback global function var src = script.src || ''; var idx = src.indexOf('jsoncallback='); if (idx != -1) { var idx2 = src.indexOf('&'); if (idx2 == -1) { idx2 = src.length; } var jsonCallback = src.substring(idx + 13, idx2); delete window[jsonCallback]; }
这样一来就趋于完美了。
完整代码
function jsonp(url, data, callback) { var xhr = $.getJSON(url + '?jsoncallback=?', data, callback); // request failed xhr.fail(function(jqXHR, textStatus, ex) { /* * in ie 8, if service is down (or network occurs an error), the arguments will be: * * testStatus: 'parsererror' * ex.description: 'xxxx was not called' (xxxx is the name of jsoncallback function) * ex.message: (same as ex.description) * ex.name: 'Error' */ alert('failed'); }); // ie 8+, chrome and some other browsers var head = document.head || $('head')[0] || document.documentElement; // code from jquery var script = $(head).find('script')[0]; script.onerror = function(evt) { alert('error'); // do some clean // delete script node if (script.parentNode) { script.parentNode.removeChild(script); } // delete jsonCallback global function var src = script.src || ''; var idx = src.indexOf('jsoncallback='); if (idx != -1) { var idx2 = src.indexOf('&'); if (idx2 == -1) { idx2 = src.length; } var jsonCallback = src.substring(idx + 13, idx2); delete window[jsonCallback]; } }; }
以上程式碼在IE8、IE11、Chrome、FireFox、Opera、360下測試通過,其中360是IE核心版本,其他瀏覽器暫時未測。
希望本文對大家學習,幫助大家解決jQuery使用JSONP時產生的錯誤。

实现方法:1、用“$("img").delay(毫秒数).fadeOut()”语句,delay()设置延迟秒数;2、用“setTimeout(function(){ $("img").hide(); },毫秒值);”语句,通过定时器来延迟。

修改方法:1、用css()设置新样式,语法“$(元素).css("min-height","新值")”;2、用attr(),通过设置style属性来添加新样式,语法“$(元素).attr("style","min-height:新值")”。

区别:1、axios是一个异步请求框架,用于封装底层的XMLHttpRequest,而jquery是一个JavaScript库,只是顺便封装了dom操作;2、axios是基于承诺对象的,可以用承诺对象中的方法,而jquery不基于承诺对象。

增加元素的方法:1、用append(),语法“$("body").append(新元素)”,可向body内部的末尾处增加元素;2、用prepend(),语法“$("body").prepend(新元素)”,可向body内部的开始处增加元素。

在jquery中,apply()方法用于改变this指向,使用另一个对象替换当前对象,是应用某一对象的一个方法,语法为“apply(thisobj,[argarray])”;参数argarray表示的是以数组的形式进行传递。

删除方法:1、用empty(),语法“$("div").empty();”,可删除所有子节点和内容;2、用children()和remove(),语法“$("div").children().remove();”,只删除子元素,不删除内容。

on()方法有4个参数:1、第一个参数不可省略,规定要从被选元素添加的一个或多个事件或命名空间;2、第二个参数可省略,规定元素的事件处理程序;3、第三个参数可省略,规定传递到函数的额外数据;4、第四个参数可省略,规定当事件发生时运行的函数。

去掉方法:1、用“$(selector).removeAttr("readonly")”语句删除readonly属性;2、用“$(selector).attr("readonly",false)”将readonly属性的值设置为false。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Dreamweaver Mac版
視覺化網頁開發工具

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Dreamweaver CS6
視覺化網頁開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版
SublimeText3 Linux最新版