正常發請求時,curl
示例:javascript
$ curl https://shanyue.tech/api/user?id=100 { "id": 100, "name": "shanyue", "wechat": "xxxxx", "phone": "183xxxxxxxx" }
使用 fetch
發送請求,示例:html
const data = await fetch('https://shanyue.tech/api/user?id=100', { headers: { 'content-type': 'application/json', }, method: 'GET', }).then(res => res.json())
請求數據後,使用一個函數來處理數據前端
handleData(data)
JSONP
,全稱 JSON with Padding
,爲了解決跨域的問題而出現。雖然它只能處理 GET 跨域,雖然如今基本上都使用 CORS 跨域,但仍然要知道它,畢竟面試會問。java
curl
示例node
$ curl https://shanyue.tech/api/user?id=100&callback=padding padding({ "id": 100, "name": "shanyue", "wechat": "xxxxx", "phone": "183xxxxxxxx" })
對於正常的請求有何不一樣一目瞭然: 多了一個 callback=padding, 而且響應數據被 padding 包圍,這就是 JSONPgit
那請求數據後,如何處理數據呢?此時的 padding 就是處理數據的函數github
window.padding = handleData
這裏實現一個 jsonp 函數面試
function jsonp_simple ({ url, onData, params }) { const script = document.createElement('script') // 1、默認 callback 函數爲 padding script.src = `${url}?${stringify({ callback: 'padding', ...params })}` // 2、使用 onData 做爲 window.padding 函數,接收數據 window['padding'] = onData document.body.appendChild(script) }
此時會有一個問題: window.padding 函數會污染全局,若是有多個請求發送如何處理?json
使 jsonp 的回調函數名做爲一個隨機變量,代碼以下api
function jsonp ({ url, onData, params }) { const script = document.createElement('script') // 1、爲了不全局污染,使用一個隨機函數名 const cbFnName = `JSONP_PADDING_${Math.random().toString().slice(2)}` // 2、默認 callback 函數爲 cbFnName script.src = `${url}?${stringify({ callback: cbFnName, ...params })}` // 3、使用 onData 做爲 cbFnName 回調函數,接收數據 window[cbFnName] = onData; document.body.appendChild(script) } // 發送 JSONP 請求 jsonp({ url: 'http://localhost:10010', params: { id: 10000 }, onData (data) { console.log('Data:', data) } })
完整代碼可見山月博客的 github 倉庫: https://github.com/shfshanyue...
JSONP 實現完整代碼:
function stringify (data) { const pairs = Object.entries(data) const qs = pairs.map(([k, v]) => { let noValue = false if (v === null || v === undefined || typeof v === 'object') { noValue = true } return `${encodeURIComponent(k)}=${noValue ? '' : encodeURIComponent(v)}` }).join('&') return qs } function jsonp ({ url, onData, params }) { const script = document.createElement('script') // 1、爲了不全局污染,使用一個隨機函數名 const cbFnName = `JSONP_PADDING_${Math.random().toString().slice(2)}` // 2、默認 callback 函數爲 cbFnName script.src = `${url}?${stringify({ callback: cbFnName, ...params })}` // 3、使用 onData 做爲 cbFnName 回調函數,接收數據 window[cbFnName] = onData; document.body.appendChild(script) }
JSONP 服務端適配相關代碼:
const http = require('http') const url = require('url') const qs = require('querystring') const server = http.createServer((req, res) => { const { pathname, query } = url.parse(req.url) const params = qs.parse(query) const data = { name: 'shanyue', id: params.id } if (params.callback) { str = `${params.callback}(${JSON.stringify(data)})` res.end(str) } else { res.end() } }) server.listen(10010, () => console.log('Done'))
JSONP 頁面調用相關代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script src="./index.js" type="text/javascript"></script> <script type="text/javascript"> jsonp({ url: 'http://localhost:10010', params: { id: 10000 }, onData (data) { console.log('Data:', data) } }) </script> </body> </html>
從中克隆代碼: 山月博客的 github 倉庫
index.js
: jsonp 的簡單與複雜實現server.js
: 服務器接口形式demo.html
: 前端如何調用 JSONP// 開啓服務端 $ node server.js // 對 demo.html 起一個服務,而且按照提示在瀏覽器中打開地址,應該是 http://localhost:5000 // 觀察控制檯輸出 JSONP 的回調結果 $ serve .
本文收錄於 GitHub 日問: DailyQuestion,內含大廠內推機會、面經大全及若干面試題,天天學習五分鐘,一年進入大廠中。