要點總結
這篇文章於 2016 年 6 月 23 日進行了更新,以解決質量問題。舊文章的相關評論已被刪除。如果您正在開發基於Web 的應用程序,並且嘗試從不受您控制的域加載數據,則您很可能在瀏覽器的控制台中看到以下消息:XMLHttpRequest cannot load https://www.php .cn/link/0df0dbfc4725c2259dc0bb045e9bf6d2. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.php.cn/link/28db3b5e7bfadf38b792da7192530ac1' is therefore not allowed access.
在本文中,我們將探討導致此錯誤的原因,以及如何通過使用 jQuery 和 JSONP 來進行跨域 Ajax 調用來解決此問題。
同源策略
常規網頁可以使用 XMLHttpRequest 對象向遠程服務器發送和接收數據,但是同源策略限制了它們可以執行的操作。這是瀏覽器安全模型中的一個重要概念,它規定網頁瀏覽器可能只允許頁面 A 上的腳本訪問頁面 B 上的數據,如果這兩個頁面具有相同的來源。頁面的來源由其協議、主機和端口號定義。例如,此頁面的來源是“https”、“www.sitepoint.com”、“80”。同源策略是一種安全機制。它可以防止腳本從您的域讀取數據並將其發送到它們的服務器。如果沒有這個,惡意網站很容易將您的會話信息抓取到另一個站點(例如 Gmail 或 Twitter),並代表您執行操作。不幸的是,它還會導致我們上面看到的錯誤,並且經常會給試圖完成合法任務的開發人員帶來麻煩。
失敗的示例
讓我們看看什麼不起作用。這是一個位於不同域上的 JSON 文件,我們希望使用 jQuery 的 getJSON 方法加載它。
$.getJSON( "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-1.json", function(json) { console.log(json); } );
如果您在瀏覽器中打開控制台嘗試一下,您將看到類似於上面提到的消息。那麼我們能做什麼呢?
可能的解決方法
幸運的是,並非所有內容都受同源策略的影響。例如,完全可以將圖像或腳本從不同域加載到您的頁面中——當您從 CDN 包含 jQuery(例如)時,您正在執行此操作。這意味著我們可以創建一個 <script>
標籤,將其 src
屬性設置為我們的 JSON 文件,並將其註入頁面。
var script = $("<script>", { src: "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-1.json", type: "application/json" } ); $("head").append(script);
雖然這有效,但對我們幫助不大,因為我們無法訪問它包含的數據。
JSONP 入門
JSONP(代錶帶填充的 JSON)基於此技術,並為我們提供了一種訪問返回數據的方法。它是通過讓服務器返回包含函數調用(“填充”)的 JSON 數據來實現的,然後瀏覽器可以解釋該函數調用。此函數必須在評估 JSONP 響應的頁面中定義。
讓我們看看之前的示例是什麼樣的。這是一個更新的 JSON 文件,它將原始 JSON 數據包裝在一個 jsonCallback
函數中。
function jsonCallback(json){ console.log(json); } $.ajax({ url: "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-2.json", dataType: "jsonp" });
這會將預期結果記錄到控制台中。我們現在有了(儘管相當有限)跨域 Ajax。
第三方 API
一些第三方 API 允許您指定回調函數的名稱,當請求返回時應執行該函數。一個這樣的 API 是 GitHub API。
在下面的示例中,我們獲取 John Resig(jQuery 創建者)的用戶信息,並使用 logResults
回調函數將響應記錄到控制台中。
function logResults(json){ console.log(json); } $.ajax({ url: "https://api.github.com/users/jeresig", dataType: "jsonp", jsonpCallback: "logResults" });
這也可以寫成:
$.getJSON("https://api.github.com/users/jeresig?callback=?",function(json){ console.log(json); });
URL 末尾的 ?
告訴 jQuery 它正在處理 JSONP 請求而不是 JSON。然後,jQuery 自動註冊回調函數,當請求返回時它會調用該函數。
如果您想了解更多關於 jQuery 的 getJSON 方法的信息,請查看:Ajax/jQuery.getJSON 簡單示例
注意事項
但正如您現在可能已經意識到的那樣,這種方法有一些缺點。
例如,JSONP 只能執行跨域 GET 請求,並且服務器必須顯式支持它。 JSONP 也並非沒有安全問題,因此讓我們簡要介紹一些其他解決方案。
使用代理
服務器端代碼不受同源策略的約束,可以毫無問題地執行跨源請求。因此,您可以創建某種代理並使用它來檢索您需要的任何數據。參考我們的第一個示例:
/* proxy.php */ $url = "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-1.json"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec ($ch); curl_close ($ch); echo $result;
在客戶端:
$.getJSON("https://www.php.cn/link/28db3b5e7bfadf38b792da7192530ac1.com/proxy.php", function(json) { console.log(json); })
但這方法也有缺點。例如,如果第三方站點使用 cookie 進行身份驗證,則此方法將不起作用。
CORS
跨源資源共享 (CORS) 是一個 W3C 規範,允許瀏覽器進行跨域通信。這是通過在響應中包含新的 Access-Control-Allow-Origin HTTP 標頭來實現的。
參考我們的第一個示例,您可以將以下內容添加到 .htaccess 文件(假設為 Apache)以允許來自不同來源的請求:
$.getJSON( "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-1.json", function(json) { console.log(json); } );
(如果您運行的服務器不是 Apache,請查看此處:https://www.php.cn/link/819e2e55be8ef0957b56ea94356bfb79)
您可以在我們最近的教程之一中了解更多關於 CORS 的信息:深入了解 CORS
結論
JSONP 允許您繞過同源策略,並在某種程度上進行跨域 Ajax 調用。它不是靈丹妙藥,當然也有其問題,但在某些情況下,當從不同來源獲取數據時,它可以證明是無價的。
JSONP 還使您可以從不同的服務中提取各種內容。許多著名的網站提供 JSONP 服務(例如 Flickr),允許您通過預定義的 API 訪問它們的內容。您可以在 ProgrammableWeb API 目錄中找到它們的完整列表。
(以下為FAQ部分,已根據原文進行調整和簡化,避免重複信息)
關於 JSONP 的常見問題解答 (FAQ)
JSON 和 JSONP 的主要區別是什麼? JSON 和 JSONP 都是用於處理服務器和 Web 應用程序之間數據的格式。主要區別在於它們處理跨域請求的方式。 JSON 由於同源策略(Web 瀏覽器中實施的安全措施)而無法支持跨域請求。另一方面,JSONP 通過使用填充方法來繞過此策略,允許從與客戶端不同的域的服務器請求數據。
JSONP 如何繞過同源策略? JSONP 通過使用填充或“填充請求”方法來繞過同源策略。在此方法中,客戶端通過將回調函數附加到 URL 來請求不同域的服務器的數據。然後,服務器將請求的數據包裝在此函數中並將其發送回客戶端。客戶端執行此函數,從而訪問數據。此方法允許 JSONP 克服同源策略施加的跨域限制。
JSONP 安全嗎? 雖然 JSONP 為同源策略提供了一種解決方法,但它確實存在自身的安全風險。由於 JSONP 涉及執行從服務器接收的腳本,因此如果服務器遭到破壞,它會為跨站點腳本 (XSS) 攻擊打開可能性。因此,務必僅與受信任的來源一起使用 JSONP。
JSONP 可以處理錯誤響應嗎? 與 JSON 不同,JSONP 沒有內置的錯誤處理。如果 JSONP 請求失敗,瀏覽器不會引發錯誤,並且不會執行回調函數。要處理 JSONP 中的錯誤,您可以實現超時機制,如果在指定時間內未執行回調函數,則會觸發錯誤。
如何使用 jQuery 發出 JSONP 請求? jQuery 提供了一種簡單的方法,可以使用 $.ajax() 方法發出 JSONP 請求。您需要在 $.ajax() 設置中將 dataType 指定為“jsonp”。
JSONP 的局限性是什麼? JSONP 有一些限制。它只支持 GET 請求,不支持 POST 或其他 HTTP 方法。它還缺乏錯誤處理功能。此外,由於其繞過同源策略的方法,JSONP 會帶來安全風險。
JSONP 現在還使用嗎? 雖然JSONP 過去是進行跨域請求的流行解決方案,但如今由於CORS(跨源資源共享)的出現,其使用頻率較低,CORS 提供了一種更安全、更強大的進行跨域請求的方法。
以上是JQuery的JSONP用示例解釋了的詳細內容。更多資訊請關注PHP中文網其他相關文章!