自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

頭條面試官:一文徹底搞懂 JSONP

開發(fā) 前端
JSONP,全稱 JSON with Padding,為了解決跨域的問題而出現(xiàn)。雖然它只能處理 GET 跨域,雖然現(xiàn)在基本上都使用 CORS 跨域,但仍然要知道它,畢竟面試會(huì)問。

[[358593]]

 一個(gè)正常的請(qǐng)求: JSON

正常發(fā)請(qǐng)求時(shí),curl 示例:

  1. $ curl https://shanyue.tech/api/user?id=100 
  2.  
  3.   "id": 100, 
  4.   "name""shanyue"
  5.   "wechat""xxxxx"
  6.   "phone""183xxxxxxxx" 

使用 fetch 發(fā)送請(qǐng)求,示例:

  1. const data = await fetch('https://shanyue.tech/api/user?id=100', { 
  2.   headers: { 
  3.     'content-type''application/json'
  4.   }, 
  5.   method: 'GET'
  6. }).then(res => res.json()) 

請(qǐng)求數(shù)據(jù)后,使用一個(gè)函數(shù)來處理數(shù)據(jù)

  1. handleData(data) 

一個(gè) JSONP 請(qǐng)求

JSONP,全稱 JSON with Padding,為了解決跨域的問題而出現(xiàn)。雖然它只能處理 GET 跨域,雖然現(xiàn)在基本上都使用 CORS 跨域,但仍然要知道它,畢竟面試會(huì)問。

curl 示例

  1. $ curl https://shanyue.tech/api/user?id=100&callback=padding 
  2.  
  3. padding({ 
  4.   "id": 100, 
  5.   "name""shanyue"
  6.   "wechat""xxxxx"
  7.   "phone""183xxxxxxxx" 
  8. }) 

對(duì)于正常的請(qǐng)求有何不同一目了然: 多了一個(gè) callback=padding, 并且響應(yīng)數(shù)據(jù)被 padding 包圍,這就是 JSONP

那請(qǐng)求數(shù)據(jù)后,如何處理數(shù)據(jù)呢?此時(shí)的 padding 就是處理數(shù)據(jù)的函數(shù)

  1. window.padding = handleData 

這里實(shí)現(xiàn)一個(gè) jsonp 函數(shù)

  1. function jsonp_simple ({ url, onData, params }) { 
  2.   const script = document.createElement('script'
  3.  
  4.   // 一、默認(rèn) callback 函數(shù)為 padding 
  5.   script.src = `${url}?${stringify({ callback: 'padding', ...params })}` 
  6.   // 二、使用 onData 作為 window.padding 函數(shù),接收數(shù)據(jù) 
  7.   window['padding'] = onData 
  8.  
  9.   document.body.appendChild(script) 

此時(shí)會(huì)有一個(gè)問題: window.padding 函數(shù)會(huì)污染全局,如果有多個(gè)請(qǐng)求發(fā)送如何處理?

使 jsonp 的回調(diào)函數(shù)名作為一個(gè)隨機(jī)變量,代碼如下

  1. function jsonp ({ url, onData, params }) { 
  2.   const script = document.createElement('script'
  3.  
  4.   // 一、為了避免全局污染,使用一個(gè)隨機(jī)函數(shù)名 
  5.   const cbFnName = `JSONP_PADDING_${Math.random().toString().slice(2)}` 
  6.   // 二、默認(rèn) callback 函數(shù)為 cbFnName 
  7.   script.src = `${url}?${stringify({ callback: cbFnName, ...params })}` 
  8.   // 三、使用 onData 作為 cbFnName 回調(diào)函數(shù),接收數(shù)據(jù) 
  9.   window[cbFnName] = onData; 
  10.  
  11.   document.body.appendChild(script) 
  12.  
  13. // 發(fā)送 JSONP 請(qǐng)求 
  14. jsonp({ 
  15.   url: 'http://localhost:10010'
  16.   params: { id: 10000 }, 
  17.   onData (data) { 
  18.     console.log('Data:', data) 
  19.   } 
  20. }) 

代碼附錄

完整代碼可見山月博客的 github 倉(cāng)庫(kù): https://github.com/shfshanyue/blog/tree/master/code/jsonp/

JSONP 實(shí)現(xiàn)完整代碼:

  1. function stringify (data) { 
  2.   const pairs = Object.entries(data) 
  3.   const qs = pairs.map(([k, v]) => { 
  4.     let noValue = false 
  5.     if (v === null || v === undefined || typeof v === 'object') { 
  6.       noValue = true 
  7.     } 
  8.     return `${encodeURIComponent(k)}=${noValue ? '' : encodeURIComponent(v)}` 
  9.   }).join('&'
  10.   return qs 
  11.  
  12. function jsonp ({ url, onData, params }) { 
  13.   const script = document.createElement('script'
  14.  
  15.   // 一、為了避免全局污染,使用一個(gè)隨機(jī)函數(shù)名 
  16.   const cbFnName = `JSONP_PADDING_${Math.random().toString().slice(2)}` 
  17.   // 二、默認(rèn) callback 函數(shù)為 cbFnName 
  18.   script.src = `${url}?${stringify({ callback: cbFnName, ...params })}` 
  19.   // 三、使用 onData 作為 cbFnName 回調(diào)函數(shù),接收數(shù)據(jù) 
  20.   window[cbFnName] = onData; 
  21.  
  22.   document.body.appendChild(script) 

JSONP 服務(wù)端適配相關(guān)代碼:

  1. const http = require('http'
  2. const url = require('url'
  3. const qs = require('querystring'
  4.  
  5. const server = http.createServer((req, res) => { 
  6.   const { pathname, query } = url.parse(req.url) 
  7.   const params = qs.parse(query) 
  8.  
  9.   const data = { name'shanyue', id: params.id } 
  10.  
  11.   if (params.callback) { 
  12.     str = `${params.callback}(${JSON.stringify(data)})` 
  13.     res.end(str) 
  14.   } else { 
  15.     res.end() 
  16.   } 
  17.  
  18. }) 
  19.  
  20. server.listen(10010, () => console.log('Done')) 

JSONP 頁(yè)面調(diào)用相關(guān)代碼

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.   <meta charset="UTF-8"
  5.   <title></title> 
  6. </head> 
  7. <body> 
  8.   <script src="./index.js" type="text/javascript"></script> 
  9.   <script type="text/javascript"
  10.   jsonp({ 
  11.     url: 'http://localhost:10010'
  12.     params: { id: 10000 }, 
  13.     onData (data) { 
  14.       console.log('Data:', data) 
  15.     } 
  16.   }) 
  17.   </script> 
  18. </body> 
  19. </html> 

JSONP 實(shí)現(xiàn)代碼示例演示

從中克隆代碼: 山月博客的 github 倉(cāng)庫(kù)

文件結(jié)構(gòu)

  • index.js: jsonp 的簡(jiǎn)單與復(fù)雜實(shí)現(xiàn)
  • server.js: 服務(wù)器接口形式
  • demo.html: 前端如何調(diào)用 JSONP

快速演示

  1. // 開啟服務(wù)端 
  2. $ node server.js 
  3.  
  4. // 對(duì) demo.html 起一個(gè)服務(wù),并且按照提示在瀏覽器中打開地址,應(yīng)該是 http://localhost:5000 
  5. // 觀察控制臺(tái)輸出 JSONP 的回調(diào)結(jié)果 
  6. $ serve . 

本文轉(zhuǎn)載自微信公眾號(hào)「全棧成長(zhǎng)之路」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系全棧成長(zhǎng)之路公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 全棧成長(zhǎng)之路
相關(guān)推薦

2020-12-07 06:19:50

監(jiān)控前端用戶

2021-07-08 10:08:03

DvaJS前端Dva

2020-03-18 14:00:47

MySQL分區(qū)數(shù)據(jù)庫(kù)

2021-06-30 08:45:02

內(nèi)存管理面試

2022-06-07 10:13:22

前端沙箱對(duì)象

2019-11-06 17:30:57

cookiesessionWeb

2020-05-11 14:35:11

微服務(wù)架構(gòu)代碼

2022-04-11 10:56:43

線程安全

2023-06-13 07:04:27

2024-08-08 14:57:32

2023-11-23 06:50:08

括號(hào)

2021-08-05 06:54:05

觀察者訂閱設(shè)計(jì)

2023-04-12 08:38:44

函數(shù)參數(shù)Context

2022-03-24 08:51:48

Redis互聯(lián)網(wǎng)NoSQL

2021-10-20 08:49:30

Vuexvue.js狀態(tài)管理模式

2021-01-06 13:52:19

zookeeper開源分布式

2024-04-12 12:19:08

語(yǔ)言模型AI

2024-10-15 17:12:38

代碼父子線程開源

2019-12-04 13:50:07

CookieSessionToken

2023-01-27 18:55:37

Python內(nèi)置函數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)