摘要:表單發請求付款在服務器里面增加一個請求路徑。動態創建方法發送請求叫做方案全稱,在出來以前,無刷新局部更新頁面內容的最好的方案。
簡單的前后端交互
前面學習了這么多,都是在和頁面打交道,不管是HTML、CSS、JavaScript,DOM,都沒有跑出瀏覽器,那今天來學習下和后臺交互。
當我點擊付款按鈕時,頁面的數值會減小;當我刷新頁面時,內容不會改變,該怎么實現呢?
先寫一個簡單的node.js腳本,讓頁面能夠正常運行
創建一個文件夾里面創建兩個文件
新建一個腳本文件
新建一個index.html文件
打開服務器,就可以看到自己的頁面了
腳本文件var http = require("http") var fs = require("fs") var url = require("url") var port = process.argv[2] if(!port){ console.log("請指定端口號好不啦? node server.js 8888 這樣不會嗎?") process.exit(1) } var server = http.createServer(function(request, response){ var parsedUrl = url.parse(request.url, true) var pathWithQuery = request.url var queryString = "" if(pathWithQuery.indexOf("?") >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf("?")) } var path = parsedUrl.pathname var query = parsedUrl.query var method = request.method /******** 從這里開始看,上面不要看 ************/ if(path === "/"){ var string = fs.readFileSync("./index.html","utf8") response.setHeader("Content-Type","text/html;charset=utf-8") response.write(string) response.end() }else if(path === "/css/style.css"){ var string = fs.readFileSync("./css/style.css","utf8") response.setHeader("Content-Type","text/css") response.write(string) response.end() }else if(path === "/js/main.js"){ var string = fs.readFileSync("./js/main.js","utf8") response.setHeader("Content-Type","text/javascript;charset=utf-8") response.write(string) response.end() }else{ response.statusCode = 404 response.setHeader("Content-Type","text/html;charset=utf-8") response.end("找不到對應的路徑,你需要自行修改 index.js") } /******** 代碼結束,下面不要看 ************/ }) server.listen(port) console.log("監聽 " + port + " 成功 請用在空中轉體720度然后用電飯煲打開 http://localhost:" + port)HTML 文件
首頁 你的余額是100
當我們點付款的時候,100會往下減小,但是當我們刷新頁面的時候,又變成了100。
這里我們只是在瀏覽器上面操作頁面內容,數據沒有長久的存儲在數據庫里面,所以當我們刷新頁面時,它又回到初始狀態,這顯然不是我們要的效果。
我們該怎么解決這個問題呢?
用占位符替換頁面數據我們在剛才的當前文件夾中新建一個文件,作為我們的數據庫,現在我們把100元寫在數據庫里。
數據庫簡單的講就是一個能長久存儲數據的地方,文件是數據庫最簡單的形式。
touch db echo "100" > db
index.html中的100用一個占位符替代,這個占位符要和頁面中其他變量不重復,實際上頁面上的數據,前端是不需要知道的,用一個占位符站位即可,發送請求,后端程序員去讀數據庫里的內容,返回給前端。
&&&amount&&&
在腳本中if(path === "/index.html")里加一個替換占位符語句。
var amount = fs.readFileSync("./index","utf8") //文件中的數據類型是String string = string.replace("&&&amount&&&",amount)
重啟服務器后,刷新頁面后我們看到的100是數據庫里的數據,當我們點擊付款時,變化的是數據庫里面的數據,和前端沒有關系,但是當我們刷新頁面后,依舊回到初始狀態,沒有保存最新的數據。
我點付款的時候應該發送一個請求告訴服務器,請把數據庫里的100變成99,然后刷新頁面;我不對頁面做操作改變它的數據了,那我點付款的時候,發起一個請求,應該怎么做呢?
可以發請求的標簽有img、link、script、form表單,當我們點擊按鈕應該發送POST請求,因為是更新數據庫內容,所以這里只有form表單能發送POST請求。
form表單發請求在服務器里面增加一個/pay請求路徑。
if(path === "/pay" && method.toUpperCase() === "POST"){ var amount = fs.readFileSync("./db","utf8") var newAmount = amount - 1 fs.writeFileSync("./db",newAmount) response.write("success") //成功后給用戶返回 response.end() }
當我點付款的時候,會看當前頁面會跳轉到/pay路徑下的頁面,表示成功了。
點擊瀏覽器的返回上一頁,刷新下當前頁面,之前的100變成了99,無論怎么刷新或者重新打開,數據都是之前的操作過結束后的數據。
這里前端要寫的就是form表單,后端如果發現是某個路徑并且是POST請求,就去操作數據庫。
這是舊時代的操作,form表單一旦提交了都會刷新當前頁面,給用戶造成了不好的體驗。有個程序員想出了用iframe解決頁面刷新的問題,操作成功后在iframe打卡跳轉頁面。
iframe 表單刷新頁面有個程序員覺得頁面中多出一個東西總是怪怪的,絞盡腦汁又想出了動態創建img標簽的方法
動態創建img標簽發送請求有潔癖的程序員總是能想出更好的解決方法,接著來看下動態創建img標簽的發送請求的方法。
腳本中增加/pay路徑下應該這樣寫
if(path === "/pay"){ var string = fs.readFileSync("./db","utf8") var newAmount = string - 1 if(Math.random() > 0.5){ fs.writeFileSync("./db",newAmount) response.setHeader("Content-type","image/jpeg") response.statusCode = 200 response.write(fs.readFileSync("./1.jpeg")) }else{ response.statusCode = 400 response.write("alert("fail")") } response.end() }
因為img標簽,只能發送GET請求,所以這里就不做method判斷了。
JS 文件
button.addEventListener("click",function(e){ let image = document.createElement("img") image.src = "/pay" img.onload = function(){ alert("success") window.location.reload() } img.onerror = function(){ alert("fail") } })
onload和onerror是提示用戶成功了還是失敗,在onload里面加上一個window.location.reload()成功后會自動刷新頁面。
動態創建img標簽的方法,必須要返回真實的圖片,瀏覽器才能知道操作成功了,不然onload一直不會成功,雖然數據庫已經修改成功了,但瀏覽器只要沒接收到圖片,就會執行onerror,這也是它的局限所在——必須要返回真是圖片。
同時刷新頁面會造成瀏覽器重新渲染,所以當瀏覽器接收到響應時,前端應該在頁面上自動減1,用戶并不會知道這中間發生了什么。
動態創建script標簽——SRJ方案用a標簽發送請求太浪費資源了,這時又有人想出了用script標簽發請求,這就是優秀程序員和普通程序員之間的差距啊。
下面來看看是怎么實現的:
button.addEventListener("click",function(){ var script = document.createElement("script") script.src = "/pay" document.body.appendChild(script) //必須要將創建出來的Script放在頁面中才可以 script.onload = function(){ alert("sucess") } })
/pay路徑下的代碼
if(path === "/pay"){ var string = fs.readFileSync("./db","utf8") var newAmount = string - 1 fs.writeFileSync("./db",newAmount) response.setHeader("Content-type","application/js") response.statusCode = 200 response.write("alert("success1")") response.end() }
當我點付款時,成功后首先執行腳本里面的script,執行完了之后才執行main.js內的onload。
因為腳本中的script先執行,所以main.js里面就不需要提示用戶了,直接后臺給提示內容就可以了。
如下:
response.write(`alert("success") amount.innerText = amount.innerText -1`) //ES6字符串方法
到這里聰明的你應該也發現了一個問題,當我點付款時,不管成功與否都會創建一個script,對于程序員來說是無法接受的,所以要用onload和onerror去監聽,不管成功與否都將它刪除掉。這里雖然刪掉了但它還是在內存中。
script.onload = function(e){ e.currentTarget.remove() } script.onerror = function(e){ e.currentTarget.remove() }
動態創建script方法發送請求叫做——SRJ方案(全稱 Server rendered javascript),在 ajax 出來以前,無刷新局部更新頁面內容的最好的方案。
請求另一個網站的script在頁面中引入一個script時,一定要在當前域名嗎?
NO!!!我們在頁面中引入的各種庫,不都是引入別人的網站的script嘛
那這樣的話,是不是可以操作別人網站的/pay,所以GET請求太不安全,太容易偽造了,所以大部分的/pay都用POST請求去做。
PORT=8002 node index.js 可以開多個端口
SRJ方案前后端耦合太緊密了,需要后端對頁面了解太清楚。
其實前端提供一個xxx() API就可以了。
response.write(` xxx.call(undefined,"success") `)
前端提供 API 的方法,其實解耦還沒有解的很干凈,我們在設置script的src時可以直接設置請求參數,腳本只需要取這個參數就可以了,至于具體叫什么名字不重要
script.src = "http://baidu.com:8002/pay?callbackName=xxx"
response.write(` ${query.callbackName}.call(undefined,"success") `)
到這里已經是很好的方案了,但是有一個問題是,調用函數傳遞的參數,前端怎么知道呢?如果不確定,到時候出了問題就要各自扯皮了,這時候JSON應運而出。
JSONP方案JSONP用JSON的格式進行參數傳遞,解決了兩個網站之間的交流。至于為什么叫JSONP,應該是大括號左邊的叫做左padding,右邊的叫做右padding,連接起來就叫做JSONP。
${query.callbackName}.call(undefined,{ "success": true "left": ${newAmount} })用文字敘述 JSONP
請求方:qq.com的前端程序員(瀏覽器)
響應方:baidu.com的后端程序員(服務器)
請求方創建script ,src指向相應方同事傳一個查詢參數 ?callbackName=xxx
響應方根據查詢參數callbackName,構造形如xxx.call(undefined,"你要的數據")這樣的響應
瀏覽器接收到響應,xxx.call(undefined,"你要的數據")
那么請求方就知道了它要的數據
這就是JSONP
約定:callbackName -> callback
xxx -> 隨機數
按照約定寫一下
button.addEventListener("click",funcion(e){ let script = document.createElement("script") let functionName = parseInt(Math.random()*1000000) //這個函數名是隨機數 window[functionName] = function(result){ //result是服務器返回的結果 if(result === "success"){ amount.innerText = amount.innerText - 1 } } script.src = "http://baidu.com:8002?callback=" + functionName //寫在參數里面 document.body.appendChild(script) script.onload = function(e){ e.currentTarget.remove() delete window[functionName] //如果成功了要干掉這個函數 } script.onerror = function(e){ alert("false") e.currentTarget.remove() delete window[functionName] //如果失敗了也要干掉這個函數 } })jQuery實現
用jQuery就能非常方便的使用
button.addEventListener("click",function(){ $.ajax({ url: "http://baidu.com:8002/pay" dataType: "JSONP" success:function(response){ console.log(response) } }) })JSONP為什么不支持POST請求
因為JSONP是通過動態創建script實現的
動態創建script只有GET請求沒有POST請求
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95290.html
摘要:隨后也跟進抄襲了,取名,并被納入規范全稱翻譯成中文異步的和技術的核心是對象簡稱,可以在不刷新頁面頁面也能取得新的數據。注意請求和響應都不包含信息。 JSONP發展 了解了JSONP技術棧后,知道了JSONP是AJAX出現之前后端交互最好的解決方案,但它依然沒解決問題,用JSONP只能發送GET請求,不能發其他請求 form表單可以發GET請求,也可以發POST請求,POST請求沒有請求...
摘要:概述項目是基于,成品是一個移動端的音樂播放器,來源于的實戰課程。播放器是全局組件,放在下面,通過傳遞數據,觸發提交,從而使播放器開始工作。將請求的數據格式化后再通過傳遞,組件間共享,實現歌曲的播放切換等。 概述 項目是基于Vue.js,成品是一個移動端的音樂播放器,來源于imooc的實戰課程。自己動手實踐并加以修改拓展。項目的大致流程是Vue-cli構建開發環境,分析需求,設計構思,規...
摘要:寫在前面沒錯,這就是慕課網上的那個音樂播放器,后臺是某音樂播放器的線上接口扒取,雖然這類項目寫的人很多,但不得不說這還是個少有的適合提升的好項目,做這個項目除了想寫一個比較大并且功能復雜的項目,主要原因是要拿它來應對面試,也確實對我的業務能 寫在前面 沒錯,這就是慕課網上的那個vue音樂播放器,后臺是某音樂播放器的線上接口扒取,雖然這類項目寫的人很多,但不得不說這還是個少有的適合vu...
閱讀 1887·2021-11-15 11:46
閱讀 1077·2021-10-26 09:49
閱讀 1819·2021-10-14 09:42
閱讀 3374·2021-09-26 09:55
閱讀 827·2019-08-30 13:58
閱讀 1024·2019-08-29 16:40
閱讀 3462·2019-08-26 10:27
閱讀 601·2019-08-23 18:18