cookie 若是非要用漢語理解的話應該是 一段小型文本文件,由網景的創始人之一的 盧 蒙特利在93年發明。上篇是熟悉一下注冊的大體流程,下篇熟悉登陸流程以及真正的Cookiejavascript
咱們打開網站,瀏覽網站,最多見的兩個操做就是註冊以及登陸,因此有必要探索一下這兩個功能如何實現的。css
本地模擬,當輸入localhost:8080/sign_up
的時候,瀏覽器發起get
請求,服務器給你響應sign_up.html
html
//服務器端代碼 if (path === '/sign_up' && method === 'GET') { let string = fs.readFileSync('./sign_up.html', 'utf8') response.statusCode = 200 response.setHeader('Content-Type', 'text/html;charset=utf-8') response.write(string) response.end() }
在寫sign_up.html
的時候,注意幾點css知識:前端
body, html{height: 100%} //或者 body{min-height: 100%} html{height: 100%} //不能這麼寫 body, html{min-height: 100%}
固然了,實際上這麼寫就能夠了java
body{min-height: 100vh}
label
標籤是display: inline
,不能設置寬度,行內元素則會根據行內內容自適應寬度,因此行內元素設置width是沒有效果的。改爲inline-block就能夠了
既然是註冊的需求,那麼咱們首要關注的點就是--用戶的註冊信息咱們如何得到呢node
選擇合理的數據結構存儲數據是很重要的。git
input
的name
可使用數組存儲input
的value
應該使用hash
,也就是對象來存儲。hash+[]
的組合。//使用jq來寫 let hash = {} let $form = $('#signUpForm') $form.on('submit', (e) => { e.preventDefault() //不用form表單的默認提交,而是使用咱們的的ajax提交 let need = ['email', 'password', 'password_confirmation'] need.forEach((name) => { let value = $form.find(`[name=${name}]`).val() hash[name] = value })
最終hash
裏面存儲的就是github
{ 'email': '...', 'password': '...', 'password_confirmation': '...' }
到目前爲止咱們把用戶的數據封裝到了一個對象裏面了。web
不過在把hash用ajax發出去以前要先進行一些必要的非空驗證ajax
主要是檢測郵箱是否爲空、密碼是否爲空、兩次輸入的密碼是否一致。
//發起請求以前驗證是否爲空 if (hash['email'] === '') { $form.find('[name="email"]').siblings('.errors').text('請您輸入郵箱') return false //精髓啊,否則沒用了 } if (hash['password'] === '') { $form.find('[name="password"]').siblings('.errors').text('請您輸入密碼') return false //精髓啊,否則沒用了 } if (hash['password_confirmation'] === '') { $form.find('[name="password_confirmation"]').siblings('.errors').text('請您再次輸入確認密碼') return false //精髓啊,否則沒用了 } if (hash['password'] !== hash['password_confirmation']) { $form.find('[name="password_confirmation"]').siblings('.errors').text('兩次輸入密碼不匹配') return false //精髓啊,否則沒用了 }
$form.find('.errors').each((index, span) => { $(span).text('') })
使用上述的jq代碼來解決這個bug便可。
非空驗證完了以後,意味着瀏覽器收集用戶數據的工做完成了,能夠把hash發到服務器端了,接下來就是ajax請求了。
$.post('/sign_up', hash) .then((response) => { //成功了就打印這個 console.log(response) }, () => { //錯誤了打印這個 })
由於formData是一段一段上傳的(具體緣由略複雜,能夠取極限法,若是formdata不少,不可能一會兒上傳過來),本身不會寫,就去搜索代碼片斷解析formdata
google: node get post data
把得到的代碼封裝成了一個函數
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) }) } ) }
如何使用上述代碼片斷呢
... if (path === '/sign_up' && method === 'POST') { readBody(request).then((body) => { let strings = body.split('&') //['email=1', 'password=2', 'password_confirmmation=3'] let hash = {} strings.forEach(string => { //想獲得相似這種的 string == 'email=1' let parts = string.split('=') //再用=分割,獲得['email', '1'] let key = parts[0] let value = parts[1] hash[key] = decodeURIComponent(value)//hash['email'] = '1' }) let {email, password, password_confirmation} = hash //ES6的解構賦值 } ...
當服務器端接收到了全部的formdata數據後,實際上是一串形如email=1&password=2&password_confirmation=3
的字符串,因此咱們考慮使用&
字符分割成數組。
['email=1', 'password=2', 'confirmation=3']
的數組以後,咱們爲了獲得string = 'email=1'
這種形式的,開始遍歷數組,把數組的每一個元素按照=
分割,獲得 [email, 1]
hash+[]
方法,處理成hash既然服務器端已經得到了formdata
了,那麼應該進行一下簡單的校驗,好比郵箱的格式,沒有問題了就把數據存到數據庫裏面。(目前校驗水平很入門,沒有涉及到完備的註冊校驗功能)
上一節咱們把formdata完美的封裝到了hash裏面,爲了校驗咱們要把hash再拆開一個一個的看
或許這麼作是最直接的
let email = hash['emai'] let password = hash['password'] let password_confirmation = hash['password_confirmation']
不過ES6提供了一種解構賦值的語法糖,很甜很貼心……
let {email, password, password_confirmation} = hash
好了,咱們這一步就先看看郵箱格式是否正確。
我是菜鳥級校驗郵箱,看到了郵箱的獨特標誌---@
,最起碼有這個標誌才叫郵箱吧,也就是說沒有這個標誌,我就能夠認爲郵箱格式不對啊,翻譯成代碼就是
if (email.indexOf('@') === -1) { response.statusCode = 400 response.write('email is bad') //單引號只是爲了標記這是一個字符串 }
很好,目前來講,事情的發展都很正常,直到一個bug的到來。
一個合法的郵箱,卻進入了非法郵箱處理的代碼片斷裏面……
毫無疑問,郵箱是合法的,代碼也是合理的,那麼出問題的必然是我,某個地方的理解有問題。
console.log(email.indexOf('@')) console.log(email)
沒錯,email
這個字符串的@
索引真的是-1,但是個人郵箱寫的明明有@
啊。
爲啥呢,接着又打印出了email
的內容,終於真相大白了,email
字符串裏面真的沒有@
,
卻發現了一串你沒想到的%40
,(⊙v⊙)嗯,沒錯了,這就是我認爲的那個@
的另外一個形態。
%40
哪來的呢Google走起,在w3schools的HTML URL Encoding Reference找到了解釋(不是國內的w3school……)
URL encoding converts characters into a format that can be transmitted over the Internet.
URL編碼把字符轉化成了一種能夠在互聯網上傳播的格式,也就是說,我在網頁上看到的字符是被URL編碼處理的結果。
搞定這個以前,文檔先要讓你明白啥是URL
Web browsers request pages from web servers by using a URL.The URL is the address of a web page, like: https://www.w3schools.com.
Web瀏覽器經過使用URL從Web服務器請求頁面。 該網址是網頁的地址,例如:https://www.w3schools.com。
複習一下URL的組成6部分:
https://www.baidu.com/s?wd=he... 經過這個你就能夠訪問到一個 "惟一的" 網址
名字 | 做用 |
---|---|
https: | 協議 |
www.baidu.com | 域名 |
/s | 路徑 |
wd=hello&rsv_spt=1 | 查詢參數 |
#5 | 錨點 |
端口 | 默認80 |
複習完了URL
,繼續搞URL編碼
URLs can only be sent over the Internet using the ASCII character-set.Since URLs often contain characters outside the ASCII set, the URL has to be converted into a valid ASCII format.
URL encoding replaces unsafe ASCII characters with a "%" followed by two hexadecimal digits.
URLs cannot contain spaces. URL encoding normally replaces a space with a plus (+) sign or with %20.
%
後面緊跟着兩個16進制數字的編碼格式來代替不安全的ASCII碼錶20%
來代替空格。繼續往下翻,找到了%40
。
因此要把value
的值解碼回去
hash[key] = decodeURIComponent(value)
decodeURIComponent()
方法用於解碼由 encodeURIComponent
方法或者其它相似方法編碼的部分統一資源標識符(URI)。畢竟URL
屬於URI
。
若是有了錯,須要提示用戶錯了,後端寫的代碼,用戶不必定看的懂,須要前端潤色一下使用戶看懂,或者前端和後端溝通一下,maybe後端脾氣很差,前端也是暴脾氣,因此應該選擇一個先後端都要用的東西作橋樑,很明顯JSON
是完美的候選人。
if (email.indexOf('@') === -1) { response.statusCode = 400 response.setHeader('Content-Type', 'application/json;charset=utf-8') //直接告訴瀏覽器我是json response.write(` { "errors": { "email": "invalid" } } `) }
這就合理多了,後臺只管寫個json給前臺看,其餘無論了,前臺翻譯一下給用戶看嘍~
那麼前臺如何得到這個json
呢
$.post('/sign_up', hash) .then((response) => { //成功了就打印這個 console.log(response) }, (request, b, c) => { console.log(request) console.log(b) console.log(c) })
忘記了錯誤函數裏面的參數是啥了,那就都打印出來看看。
能夠看到,若是沒用JSON的話,request對象裏面有一個後端寫的responseText屬性能夠利用。
設置了Content-Type:application/json;charset=utf-8
以後,能夠利用多出來的responseJSON
屬性,得到json的內容啊。
最終失敗函數裏面寫
(request) => { let {errors} = request.responseJSON if (errors.email && errors.email === 'invalid') { $form.find('[name="email"]').siblings('.errors').text('您輸入的郵箱錯啦') } }
var users = fs.readFileSync('./db/users', 'utf8') try { users = JSON.parse(users) //[] JSON也支持數組 } catch (exception) { users = [] } let inUse = false for (let i = 0; i < users.length; i++) { let user = users[i] if (user.email === email) { inUse = true break } } if (inUse) { response.statusCode = 400 response.setHeader('Content-Type', 'application/json;charset=utf-8') response.write(` { "errors": { "email": "inUse" } } `) }
本文並無使用真正意義上的數據庫,只是使用了簡單的db文件作數據庫,其實就是存的數組,也就是users其實就是數組[]
。
try{}catch(){}
,是由於一旦除了錯,能夠將其初始化爲空數組,後續代碼能夠繼續執行,可能並不嚴謹,不過本文是側重瞭解註冊的思路的。一樣的,若是郵箱已經存在了,就提示用戶
if (errors.email && errors.email === 'inUse') { $form.find('[name="email"]').siblings('.errors').text('這個郵箱已被註冊啦') }
後端校驗必須很嚴格,由於能夠經過curl
越過前端的校驗。
沒有錯誤以後,就能夠把信息寫到數據庫裏面啦
users.push({email: email, password: password})//是個對象啊 var usersString = JSON.stringify(users) fs.writeFileSync('./db/users', usersString) response.statusCode = 200
users實現是個對象,而對象是內存裏面的東西,數據庫裏面應該存儲的是字符串,因此用了JSON.stringify(users)
好啦,上篇註冊篇結束啦,下篇講一講如何登陸以及Cookie
登場
相關代碼見sign_up.html