JSONP是個什麼鬼?
來自專欄 余咖咖的技術路
花了一天的時間學習JSONP,總結一下以後方便回顧。在了解什麼是JSONP前,需要先了解什麼是資料庫,如何向伺服器進行請求得到響應,可以用那些方式發送請求?如何向不同的伺服器發送請求並獲得響應?然後推出啥是JSOPN?內容有些長~~
一、資料庫是什麼?
1、文件系統就是一種資料庫:能長久存數據,能夠對內容進行增、刪、改、儲存
2、MySQL是一種資料庫
二、向資料庫做加法
要做的流程如下:
點擊「提交1元錢」發送請求給伺服器,伺服器修改資料庫內容,響應返回所需數據。用兩種方式來做:圖片請求;script請求;
方案一:用圖片的src向伺服器發送get請求
html代碼如下:
<body> <p>賬戶金額:<span id="amount">!!!amount!!!</span></p> <button id="button">付款1元錢</button> <script> button.addEventListener(click, (e)=>{ let image = document.createElement(img) image.src = /pay image.onload = function(){ // 狀態碼是 200~299 則表示圖片請求成功 alert(成功) } amount.innerText = amount.innerText -1 image.onerror = function(){ // 狀態碼大於等於 400 則表示圖片請求失敗 alert(失敗) } }) </script></body>
其中!!!amount!!!表示一個佔位符,後端通過獲取這個佔位符把資料庫里的內容賦值給它。
解釋:當用戶點擊button按鈕的時候,用圖片發送了路徑為/pay的GET請求給伺服器。伺服器收到後執行下面的代碼,依次是:
1、判斷路徑
2、讀取資料庫的內容,假如是9966。原始數據設置的是10000
3、在最新的內容減1,並保存給變數newAmount
4、把newAmount保存到資料庫,那麼這個時候的值應該為9965
5、確定返回給瀏覽器的內容類型為 image/jpg
6、返回一張圖片
7、結束
伺服器代碼如下:
if(path === /){ let string = fs.readFileSync(./index.html,utf8) let amount = fs.readFileSync(./db.xxx,utf8) //db.xxx文件儲存字元串10000 string = string.replace(!!!amount!!!,amount) response.statusCode = 200 response.setHeader(Content-Type, text/html;charset=utf-8) response.write(string) response.end() }else if(path === /style.css){ let string = fs.readFileSync(./style.css,utf8) response.statusCode = 200 response.setHeader(Content-Type, text/css;charset=utf-8) response.write(string) response.end() }else if(path ===/pay){ let amount = fs.readFileSync(./db.xxx,utf8) var newAmount = amount -1 fs.writeFileSync(./db.xxx,newAmount) response.setHeader(Content-Type, image/jpg) response.write(fs.readFileSync(./1.jpg)) response.end() }else{ response.statusCode = 404 response.setHeader(Content-Type, text/html;charset=utf-8) response.write(嗚嗚嗚) response.end() }
image發送get請求的缺點:得返回一張圖片,同時無法獲取其他的數據內容。
方案二:用script的src向伺服器發送get請求
html代碼如下:
<body> <p>賬戶金額:<span id="amount">!!!amount!!!</span></p> <button id="button">付款1元錢</button> <script> button.addEventListener(click, (e)=>{ let script = document.createElement(script) script.src = /pay document.body.appendChild(script) //image是不需要插入,但script要插入,記住 script.onload = function(e){ // 狀態碼是 200~299 則表示圖片請求成功 e.currentTarget.remove() //刪除script標籤 alert(成功) } script.onerror = function(){ // 狀態碼大於等於 400 則表示圖片請求失敗 e.currentTarget.remove() //刪除script標籤 alert(失敗) } }) </script></body>
解釋:當用戶點擊button按鈕的時候,用scrip發送了路徑為/pay的GET請求給伺服器。伺服器收到後執行下面的代碼,依次是:
1、判斷路徑
2、讀取資料庫的內容,假如是9966。原始數據設置的是10000
3、在最新的內容減1,並保存給變數newAmount
4、把newAmount保存到資料庫,那麼這個時候的值應該為9965
5、確定返回給瀏覽器的內容類型為 JavaScript
6、返回一段JS代碼,用來更改瀏覽器用戶看到的數字
7、結束
伺服器代碼如下(只有path ===/pay變動):
else if(path ===/pay){ let amount = fs.readFileSync(./db.xxx,utf8) var newAmount = amount -1 fs.writeFileSync(./db.xxx,newAmount) response.setHeader(Content-Type, application/javascript) //返回內容類型為 js response.write(` amount.innerText=amount.innerText-1 `) //返回JS代碼執行,賬戶餘額減1 response.end()}
script請求與image請求相比優劣:不用返回一個圖片,速度回更快一些,同時可以返回其他的內容。但動態創建的script會被執行,響應結束立刻刪除e.currentTarget.remove()
這種技術就叫做 SRJ - Server Rendered JavaScript
這種技術就叫做 SRJ - Server Rendered JavaScript
這種技術就叫做 SRJ - Server Rendered JavaScript
三、跨域SRJ - JSONP
1、什麼是JSONP(文字解釋)
2、代碼解釋
html代碼如下:
<body> <p>賬戶金額:<span id="amount">!!!amount!!!</span></p> <button id="button">付款1元錢</button> <script> button.addEventListener(click, (e)=>{ /***以下內容為伺服器獲取參數返回相關值並調用的函數***/ let functionName = frank+parseInt(Math.random()*10000,10) //frank12312423423 window[functionName] = function(result){ if(result === success){ amount.innerText = amount.innerText -1 }else{ } } /******以下內容為動態創建script發送請求,提供參數*********/ let script = document.createElement(script) script.src = http://jack.com:8002/pay?callbackName=+functionName document.body.appendChild(script) //image是不需要插入,但script要插入,記住 script.onload = function(e){ // 狀態碼是 200~299 則表示圖片請求成功 e.currentTarget.remove() //刪除script標籤 delete window[functionName] } script.onerror = function(){ // 狀態碼大於等於 400 則表示圖片請求失敗 e.currentTarget.remove() //刪除script標籤 delete window[functionName] } }) </script></body>
解釋:請求方為http://frank.com,請求http://jack.com的伺服器(響應方),通過動態script標籤來請求的。伺服器收到請求後執行:
1、判斷路徑
2、讀取資料庫的內容,假如是9966。原始數據設置的是10000
3、在最新的內容減1,並保存給變數newAmount
4、把newAmount保存到資料庫,那麼這個時候的值應該為9965
5、確定返回給瀏覽器的內容類型為 JavaScript
6、返回內容為:用${query.callbackName}獲取瀏覽器提供的參數yyy,返回請求方所需要的數據,可以是JSONP
7、結束
伺服器代碼如下:
else if(path ===/pay){ let amount = fs.readFileSync(./db.xxx,utf8)//100 var newAmount = amount -1 fs.writeFileSync(./db.xxx,newAmount) response.setHeader(Content-Type, application/javascript) response.write(` ${query.callbackName}.call(undefined,{ "success":true, "left":${newAmount} `}) ) response.end() }
約定:
1、callbackName 必須叫做 callback / jQuery callback
2、funcitonName 為 隨機數 frank12312312312321325()
3、用jquery來實現JSONP,代碼更加的簡潔
伺服器代碼不變
html代碼如下:
<body> <p>賬戶金額:<span id="amount">!!!amount!!!</span></p> <button id="button">付款1元錢</button <script> button.addEventListener(click, (e)=>{ //這個方法不是ajax,只是一個動態script $.ajax({ url: "http://jack.com:8002/pay", dataType: "jsonp", success: function( response ) { if(response === success){ amount.innerText = amount.innerText - 1 } } }) $.jsonp() }) </script> <script src=https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js></script></body>
解釋:url寫明響應方的路徑;dataType寫明回應的內容類型;當響應成功執行什麼樣的函數;其他複雜的刪減內容jQuery已經做完了。注意這個方法不是ajax,只是一個動態script進行跨域請求,可以叫做JSONP。
四、兩個問題
1、什麼是JSONP
2、JSONP為什麼不支持POST請求?
因為JSONP是通過動態創建script來實現的跨域請求的,而script只能發送GET請求。
附上我github代碼地址:
yuyunzhi/JSONP
推薦閱讀:
※有命令行工具能格式化json嗎?
※json 在 Python 爬蟲的應用
※這種Json如何使用Gson解析?
※使用Json.net處理json
※從零開始的 JSON 庫教程(五):解析數組