摘要:上面的寫法有個問題點擊按鈕發送請求后,客戶端一直收不到響應,就會報錯其實傳送的時是一個異步的過程,里面還沒執行完,外面就已經執行了,這邊可以用來解決下這個問題內部返回一個對象,成功調用函數,失敗調用函數,這邊就默認它會成功。
今天來研究一個小小的功能。當我們進入一個網站,它怎么判斷我是不是它的用戶?讓用戶登錄唄,如果它能正常登錄,它就是我的用戶唄?你有沒想過它是怎么判斷我是不是它用戶的?這次就來從前后端來講一講是怎么來實現這個功能的。
注冊注冊一般流程可以簡單的分為填寫信息,驗證信息,提示用戶,寫入數據庫,注冊成功,大致流程如下圖所示。
這里用 JS 完成最簡單的注冊流程,跑通邏輯,實際工作中遠比這復雜。
簡化驗證環節,只檢查郵箱是否輸入正確
注冊頁面首先準備一個最簡單的注冊頁面如,上圖所示。
CSS 這里有兩個注意點:
label和label::after不同字數的文字,兩端對齊
label和input居中對齊用vertical-align:middle
*{padding:0;margin:0;box-sizing:border-box;} body{ display: flex; justify-content: center; align-items: center; height:100vh; } .sign_in_form{ border:1px solid red; padding:20px; width:400px; } .row{ margin-bottom: 10px; } h1{ text-align: center; } input{ vertical-align: middle; } label{ vertical-align: middle; /*border:1px solid green;*/ width:5em; display: inline-block; height:20px; line-height:20px; overflow: hidden; text-align: justify; } label::after{ content:""; display: inline-block; /*border:1px solid blue;*/ width:100%; }
HTML 文件:
server 文件寫一個路由:當我們訪問首頁時,跳轉頁面(這里默認跳轉注冊頁面)
if (path === "/"){ let string = fs.readFileSync("./signUp.html","utf8") response.setHeader("Content-Type","text/html;charset=utf-8") response.statusCode = 200 response.write(string) response.end() }
至此一個簡單的登錄頁面就完成了,當我們點擊注冊按鈕時,就會像服務器發送一個請求。
發起 POST 請求
從上圖中我們可以看到,form表單可以發送一個GET,請求體變成查詢參數附在URL上,這是GET請求的一個特性,后臺通過讀取查詢參數就可以獲知請求信息。
這里就產生了一問題,賬戶密碼放在URL上太不安全了,別人一眼就能看到我的密碼,這樣肯定不行。
當然form表單可以發起POST請求,但我們這里用ajax發送請求
let $signInForm = $(".sign_in_form") let userInfoHash ={} $signInForm.on("submit",function(e){ e.preventDefault() let findUser = ["email","password","password_confirmation"] findUser.forEach((key)=>{ let value = $(this).find(`input[name=${key}]`).val() userInfoHash[key] = value }) $.post("/sign_up",hash).then( (response)=>{console.log(response)}, (response)=>{console.log(response)} ) })
當點擊注冊按鈕時,通過findUser對象提供的key,找到對應的value,用戶所填寫的信息,將被保存到userInfoHash中,通過POST請求傳遞給服務器。
服務器端做個路由,當我請求路徑為sign_up且為POST請求,里面才會執行。
if(path === "/sign_up" && method === "POST"){ let body = [] request.on("data",(chunk)=>{ body.push(chunk) }).on("end",()=>{ body = Buffer.concat(body).toString() console.log(body) }) response.statusCode = 200 response.end() }
HTTP傳送方法是將數據一段一段上傳,所以在服務器端需要分別獲取數據,然后在將他們拼接成一起,轉變成后端需要的字符串。
上面的寫法有個問題——點擊按鈕發送請求后,客戶端一直收不到響應,就會報錯
其實HTTP傳送的時是一個異步的過程,里面還沒執行完,外面就已經執行了,這邊可以用Promise來解決下這個問題
function readBody(request) { return new Promise((resolve,reject) =>{ let body = [] request.on("data",(chunk)=>{ body.push(chunk) }).on("end",()=>{ body = Buffer.concat(body).toString() resolve(body) }) }) }
readBody內部返回一個Promise對象,成功調用resolve函數,失敗調用reject函數,這邊就默認它會成功。
所以上面代碼可以改寫成:
if(path === "/sign_up" && method === "POST"){ readBody(request).then( (body)=>{ console.log(body) response.statusCode = 200 response.end() }) }
調用readBody函數后,因為Promise返回的是一個對象可以直接在后面用.then()操作,成功執行前面resolve函數,失敗執行后面reject函數,不過這里要注意,如果真出錯了真正的錯誤信息在第二個.then()的resolve函數里,如下所示:
readBody(request).then( ()=>{console.log("success"), ()=>{console.log("錯誤不執行")}).then( ()=>{console.log("error") })驗證數據
后端成功拿到數據后,這個數據是字符串的形式,后端需要把它一步步拆解出來。
let bodyArr = body.split("&") let userInfoHash = {} bodyArr.forEach((e)=>{ let part = e.split("=") userInfoHash[part[0]] = decodeURIComponent(part[1]) }) console.log(userInfoHash)
將拆分出來的數據一一對應的保存到 userInfoHash里。
從這里我們不難看出,前端想盡一切辦法把數據辦成字符串傳給后端,后端在想盡一切辦法把前端傳遞來數據拆分成能用的格式。
當然了,后臺響應的內容也是,前端拿到也是字符串。
當拿到數據后,應對數據進行驗證,是否符合要求,這里簡化起見,只驗證email中有無@符號與password和password_confirmation,如果正確就注冊成功。
response.setHeader("Content-Type","application/json;charset=utf-8") let {email,password,password_confirmation} = userInfoHash if(email.indexOf("@") === -1){ response.statusCode = 400 response.write(`{ "errors":{ "email":"invalid" } }`) }else if(password !== password_confirmation){ response.statusCode = 400 response.write(`{ "errors":{ "password_confirmation":"mismatch" } }`) }else{ response.statusCode = 200 response.write(`{ "success":"success" }`) }
這邊要注意的是@符號在nodejs會以%40的形式出現所以這邊需要對它進行轉碼。
這里要注意的是后臺提供的響應數據要用json的形式傳送給前端,如果格式不確定,前端那邊很難操作,也會造成問題的來源,后臺傳送數據時只需在響應部分加上響應頭response.setHeader("Content-Type","application/json;charset=utf-8"),前端拿到后會有相應的轉換方法。
$.post("/sign_up",hash).then( (response)=>{ let {success} = response if(success === "success"){ window.location.herf = "/sign_in" } }, (response)=>{ let {email,password_confirmation} = response.responseJSON.errors if(email === "invalid"){ $signInForm.find("input[name=email]").siblings(".error").text("郵箱錯誤") }else if(password_confirmation === "mismatch"){ $signInForm.find("input[name=password_confirmation]").siblings(".error").text("密碼不匹配") } })
根據后臺響應的信息,在頁面中提示用戶相關信息。
其實在用戶提交表單時,前端應該先阻止提交,判定一下用戶是否填寫正確,在發送請求,這樣在用戶填寫錯誤時候無需發送請求,節約資源。
if(userInfoHash.email === ""){ $signInForm.find("input[name=email]").siblings(".error").text("填郵箱呀") return }else if(userInfoHash.password === ""){ $signInForm.find("input[name=password]").siblings(".error").text("填密碼呀") return }else if(userInfoHash.password_confirmation === ""){ $signInForm.find("input[name=password_confirmation]").siblings(".error").text("確認密碼呀") return }else if(userInfoHash.password !== userInfoHash.password_confirmation){ $signInForm.find("input[name=password_confirmation]").siblings(".error").text("密碼不對呀") return }
前端檢測用戶有沒填寫,如果沒填寫的話,直接提示用戶,無需提交后臺。
存儲數據注冊成功后,把數據寫入數據庫,這里要注意,用戶隱私信息不能直接存儲在數據庫里,這里為了學習方便,故直接保存。
我們創建一個簡單的文件,當做數據庫,數據庫是以哈希表的形式存儲數據
let usersString = fs.readFileSync("./db/db","utf8") //讀取數據庫文件 let usersArr try{ usersArr = JSON.parse(usersString) //轉化成對象 }catch(exception) { usersArr = [] } let isUse = false for(let i = 0; i < usersArr.length; i++){ //遍歷 usersArr if(usersArr[i].email === email){ //如果 usersArr 中存在用戶的郵箱,已經注冊 isUse = true break } } if(isUse){ //如果郵箱存在響應前端操作提示用戶 response.statusCode = 404 response.write(`{ "errors":{ "email":"isUse" } }`) }else{ //如果不存在將注冊信息寫入數據庫 response.statusCode = 200 usersArr.push(userInfoHash) //存入剛剛讀取出來的 usersArr usersArr = JSON.stringify(usersArr) // 轉變成字符串 fs.writeFileSync("./db/db",usersArr) //存入數據庫 response.write(`{ "successes":{ "success":"success" } }`) }
如果前面都層高,最后進入寫數據庫環節:讀取數據庫內容——判斷用戶是否存在(這邊是判斷郵箱)——不存在,寫入數據庫;存在發送響應信息。
至此注冊環節全部結束,這邊要特別注意,數據庫讀取出來的內容是字符串
總結
數據類型在編程中非常重要,剛開始接觸時,老把符合JSON語法的字符串當成對象,弄清楚數據類型至關重要
前后端交互——字符串,不管是請求還是響應,都是字符串
后端與數據庫交互——字符串
沒有if...else解決不了問題,如果有加一個for循環
沒有console.log解決不了了bug,如果有那是console.log不夠多
網站登錄流程可參閱:從前后端分別學習——注冊/登錄流程2
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108387.html
摘要:昨天研究了網站的注冊流程,感興趣的可以看下從前后端分別學習注冊登錄流程今天接著研究注冊登錄流程之登錄。為解決這個問題,引入,它是由一組隨機數組合的哈希表,當用戶登錄成功,本來發放給用戶,現在變成發放給用戶。 昨天研究了網站的注冊流程,感興趣的可以看下:從前后端分別學習——注冊/登錄流程1 今天接著研究注冊/登錄流程之登錄。 登錄 首先來看一下登陸過程:showImg(https://s...
摘要:用存儲用戶路由守衛路由中設置的字段就在當中每次跳轉的路徑登錄狀態下訪問頁面會跳到如果沒有訪問任何頁面。一個簡單的保存登錄狀態的小。 Vue項目中實現用戶登錄及token驗證 先說一下我的實現步驟: 使用easy-mock新建登錄接口,模擬用戶數據 使用axios請求登錄接口,匹配賬號和密碼 賬號密碼驗證后, 拿到token,將token存儲到sessionStorage中,并跳轉到首...
摘要:其實,該復雜的東西在哪放都復雜,只不過現在更清晰一點使用不好的地方就是太繁瑣了,定義各種各種組件。。。。。 之前做了個好電影搜集的小應用,前端采用react,后端采用express+mongodb,最近又將組件間的狀態管理改成了redux,并加入了redux-saga來管理異步操作,記錄一些總結 在線地址 手機模式 源碼 主要功能 爬取豆瓣電影信息并錄入MongoDB 電影列表展示...
摘要:本使用創建本地服務器,在就能完成全部流程,并不需要線上服務器。路徑要與后端接口一致。后端返回成功后,前端數據中對應的元素也要刪掉,更新視圖。控制器里拿一個方法出來說一下吧,完整的代碼都在。讀取操作完成后調用釋放連接。 寫在前面 本文只是本人學習過程的一個記錄,并不是什么非常嚴謹的教程,希望和大家一起共同進步。也希望大家能指出我的問題。適合有一定基礎,志在全棧的前端初學者學習,從點擊按鈕...
閱讀 2838·2021-09-10 10:50
閱讀 2196·2019-08-29 16:06
閱讀 3199·2019-08-29 11:02
閱讀 1100·2019-08-26 14:04
閱讀 2810·2019-08-26 13:24
閱讀 2304·2019-08-26 12:16
閱讀 551·2019-08-26 10:29
閱讀 3098·2019-08-23 18:33