前幾天寫了一篇關於ajax跨域的問題,總結了常見的幾種容易混淆的問題,順帶講了些原理。今天這篇主要是說明 ajax 跨域經常使用的一種辦法 jsonp 的原理和具體實現,代碼存放在 github 上 js-cross-origin, 使用了 hapi 這個 nodejs 框架。感興趣的能夠 star 和 watch,我這幾天有空會持續更新代碼。javascript
爲了敘述方便,咱們把ajax的發出方,咱們瀏覽器上的加載好的網頁的域稱爲源域,將ajax要訪問的遠端api所在的域稱爲目標域,這兩個域不一樣。因爲瀏覽器的同源策略的,源域中的ajax訪問目標域api,會觸發跨域訪問錯誤。前端
No 'Access-Control-Allow-Origin' header is present on the requested resource.
幸運的是,script標籤目標源的js文件並不會有問題。因此聰明的前端工程師想出了一個辦法。java
網頁端插入一個script標籤,src指向目標api 的 url(只能是 get api,由於 script 加載 js 文件是 http get 方法)。這裏作一個小改動,url後面加上 query,?callback=handlenode
後端 api 處理函數接收到請求,發現有 callback 參數,則將參數值拿下來,獲得 handlegit
後端用 handle 包裝數據,返回給瀏覽器,注意,返回的 content-type 必須是 text/javascript; charset=utf-8github
網頁端 script 內容加載完成web
handle(data)
瀏覽器發現內容是 js(查看 content-type),則調用js解釋器執行 handle(data)ajax
至此,jsonp 流程完成。json
jsonp 利用 script 標籤加載 js 腳本不受同源策略的影響這個特性,繞過跨域限制。由於 script 加載 js 腳本使用的是 http get 方法,因此 jsonp 也只能訪問 GET API。 所以,後臺其餘類型的 API 也要改形成 GET 類型。segmentfault
通常成熟的 web 框架都會具有 jsonp 支持,經過簡單的配置,能夠完成 jsonp 對服務端的如下幾個要求。
讀取 callback 名,好比 handle
將數據封裝在 handle 中
將封裝好的內容做爲 js 腳本內容返回,注意 content-type 必須爲 text/javascript; charset=utf-8 以便瀏覽器正常解析執行 js
好比個人代碼中,服務器端的配置。
server.route({ method: 'GET', path:'/users', config: { jsonp: 'callback', }, handler: function (request, reply) { const jsonp = request.query.jsonp; const users = [ { id: '1', name: 'Ada'}, { id: '2', name: 'Bob' } ]; if (jsonp) { return reply(`${jsonp}(${users})`); //hapi會自動將結果的content-type設置爲 text/javascript; charset=utf-8 } else { return reply(users); // 默認 content-type 是 application/json } } });
若是運氣很差框架恰好不支持,那也沒必要擔憂,按照上面的要求,先後端約定好,實現 jsonp 並不難。
若是有其餘關於 jsonp 的問題,歡迎留言,我會將典型的問題和解答,追加到上面。