掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
一個(gè)正常的請(qǐng)求: JSON

為企業(yè)提供成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、網(wǎng)站優(yōu)化、成都全網(wǎng)營(yíng)銷推廣、競(jìng)價(jià)托管、品牌運(yùn)營(yíng)等營(yíng)銷獲客服務(wù)。成都創(chuàng)新互聯(lián)擁有網(wǎng)絡(luò)營(yíng)銷運(yùn)營(yíng)團(tuán)隊(duì),以豐富的互聯(lián)網(wǎng)營(yíng)銷經(jīng)驗(yàn)助力企業(yè)精準(zhǔn)獲客,真正落地解決中小企業(yè)營(yíng)銷獲客難題,做到“讓獲客更簡(jiǎn)單”。自創(chuàng)立至今,成功用技術(shù)實(shí)力解決了企業(yè)“網(wǎng)站建設(shè)、網(wǎng)絡(luò)品牌塑造、網(wǎng)絡(luò)營(yíng)銷”三大難題,同時(shí)降低了營(yíng)銷成本,提高了有效客戶轉(zhuǎn)化率,獲得了眾多企業(yè)客戶的高度認(rèn)可!
正常發(fā)請(qǐng)求時(shí),curl 示例:
- $ curl https://shanyue.tech/api/user?id=100
- {
- "id": 100,
- "name": "shanyue",
- "wechat": "xxxxx",
- "phone": "183xxxxxxxx"
- }
使用 fetch 發(fā)送請(qǐng)求,示例:
- const data = await fetch('https://shanyue.tech/api/user?id=100', {
- headers: {
- 'content-type': 'application/json',
- },
- method: 'GET',
- }).then(res => res.json())
請(qǐng)求數(shù)據(jù)后,使用一個(gè)函數(shù)來(lái)處理數(shù)據(jù)
- handleData(data)
一個(gè) JSONP 請(qǐng)求
JSONP,全稱 JSON with Padding,為了解決跨域的問(wèn)題而出現(xiàn)。雖然它只能處理 GET 跨域,雖然現(xiàn)在基本上都使用 CORS 跨域,但仍然要知道它,畢竟面試會(huì)問(wèn)。
curl 示例
- $ curl https://shanyue.tech/api/user?id=100&callback=padding
- padding({
- "id": 100,
- "name": "shanyue",
- "wechat": "xxxxx",
- "phone": "183xxxxxxxx"
- })
對(duì)于正常的請(qǐng)求有何不同一目了然: 多了一個(gè) callback=padding, 并且響應(yīng)數(shù)據(jù)被 padding 包圍,這就是 JSONP
那請(qǐng)求數(shù)據(jù)后,如何處理數(shù)據(jù)呢?此時(shí)的 padding 就是處理數(shù)據(jù)的函數(shù)
- window.padding = handleData
這里實(shí)現(xiàn)一個(gè) jsonp 函數(shù)
- function jsonp_simple ({ url, onData, params }) {
- const script = document.createElement('script')
- // 一、默認(rèn) callback 函數(shù)為 padding
- script.src = `${url}?${stringify({ callback: 'padding', ...params })}`
- // 二、使用 onData 作為 window.padding 函數(shù),接收數(shù)據(jù)
- window['padding'] = onData
- document.body.appendChild(script)
- }
此時(shí)會(huì)有一個(gè)問(wèn)題: window.padding 函數(shù)會(huì)污染全局,如果有多個(gè)請(qǐng)求發(fā)送如何處理?
使 jsonp 的回調(diào)函數(shù)名作為一個(gè)隨機(jī)變量,代碼如下
- function jsonp ({ url, onData, params }) {
- const script = document.createElement('script')
- // 一、為了避免全局污染,使用一個(gè)隨機(jī)函數(shù)名
- const cbFnName = `JSONP_PADDING_${Math.random().toString().slice(2)}`
- // 二、默認(rèn) callback 函數(shù)為 cbFnName
- script.src = `${url}?${stringify({ callback: cbFnName, ...params })}`
- // 三、使用 onData 作為 cbFnName 回調(diào)函數(shù),接收數(shù)據(jù)
- window[cbFnName] = onData;
- document.body.appendChild(script)
- }
- // 發(fā)送 JSONP 請(qǐng)求
- jsonp({
- url: 'http://localhost:10010',
- params: { id: 10000 },
- onData (data) {
- console.log('Data:', data)
- }
- })
代碼附錄
完整代碼可見山月博客的 github 倉(cāng)庫(kù): https://github.com/shfshanyue/blog/tree/master/code/jsonp/
JSONP 實(shí)現(xiàn)完整代碼:
- 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')
- // 一、為了避免全局污染,使用一個(gè)隨機(jī)函數(shù)名
- const cbFnName = `JSONP_PADDING_${Math.random().toString().slice(2)}`
- // 二、默認(rèn) callback 函數(shù)為 cbFnName
- script.src = `${url}?${stringify({ callback: cbFnName, ...params })}`
- // 三、使用 onData 作為 cbFnName 回調(diào)函數(shù),接收數(shù)據(jù)
- window[cbFnName] = onData;
- document.body.appendChild(script)
- }
JSONP 服務(wù)端適配相關(guān)代碼:
- 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 頁(yè)面調(diào)用相關(guān)代碼
- jsonp({
- url: 'http://localhost:10010',
- params: { id: 10000 },
- onData (data) {
- console.log('Data:', data)
- }
- })
JSONP 實(shí)現(xiàn)代碼示例演示
從中克隆代碼: 山月博客的 github 倉(cāng)庫(kù)
文件結(jié)構(gòu)
快速演示
- // 開啟服務(wù)端
- $ node server.js
- // 對(duì) demo.html 起一個(gè)服務(wù),并且按照提示在瀏覽器中打開地址,應(yīng)該是 http://localhost:5000
- // 觀察控制臺(tái)輸出 JSONP 的回調(diào)結(jié)果
- $ serve .
本文轉(zhuǎn)載自微信公眾號(hào)「全棧成長(zhǎng)之路」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系全棧成長(zhǎng)之路公眾號(hào)。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流