成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

一塊小餅干(Cookie)的故事-上篇

wums / 2419人閱讀

摘要:如果非要用漢語理解的話應(yīng)該是一段小型文本文件,由網(wǎng)景的創(chuàng)始人之一的盧蒙特利在年發(fā)明。上述的套路會一直用下去,的組合。應(yīng)該填入信息后,錯(cuò)誤信息就消失的。

cookie 如果非要用漢語理解的話應(yīng)該是 一段小型文本文件,由網(wǎng)景的創(chuàng)始人之一的盧 蒙特利在93年發(fā)明。

上篇是熟悉一下注冊的大致流程,下篇熟悉登錄流程以及真正的Cookie

實(shí)現(xiàn)基本的注冊功能

我們打開網(wǎng)站,瀏覽網(wǎng)站,最常見的兩個(gè)操作就是注冊以及登錄,所以有必要探索一下這兩個(gè)功能如何實(shí)現(xiàn)的。

本地模擬,當(dāng)輸入localhost:8080/sign_up的時(shí)候,瀏覽器發(fā)起get請求,服務(wù)器給你響應(yīng)sign_up.html

//服務(wù)器端代碼
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()
 }
CSS布局的幾個(gè)小坑

在寫sign_up.html的時(shí)候,注意幾點(diǎn)css知識:

如果想讓你的登錄頁面的body占滿整個(gè)屏幕,隨著窗口的大小變化而變化的話,可以寫

body, html{height: 100%}
//或者
body{min-height: 100%}
html{height: 100%}
//不能這么寫
body, html{min-height: 100%}

當(dāng)然了,實(shí)際上這么寫就可以了

body{min-height: 100vh}

label標(biāo)簽是display: inline,不能設(shè)置寬度,行內(nèi)元素則會根據(jù)行內(nèi)內(nèi)容自適應(yīng)寬度,所以行內(nèi)元素設(shè)置width是沒有效果的。改成inline-block就可以了

獲得用戶的數(shù)據(jù)

既然是注冊的需求,那么我們首要關(guān)注的點(diǎn)就是--用戶的注冊信息我們?nèi)绾潍@得呢

選擇合理的數(shù)據(jù)結(jié)構(gòu)存儲數(shù)據(jù)是很重要的。

每個(gè)inputname可以使用數(shù)組存儲

inputvalue應(yīng)該使用hash,也就是對象來存儲。

上述的套路會一直用下去,hash+[]的組合。

//使用jq來寫
let hash = {}
let $form = $("#signUpForm")
$form.on("submit", (e) => {
  e.preventDefault() //不用form表單的默認(rèn)提交,而是使用我們的的ajax提交
  let need = ["email", "password", "password_confirmation"]
  need.forEach((name) => {
  let value = $form.find(`[name=${name}]`).val()
  hash[name] = value
})

最終hash里面存儲的就是

{
  "email": "...",
  "password": "...",
  "password_confirmation": "..."
}

到目前為止我們把用戶的數(shù)據(jù)封裝到了一個(gè)對象里面了。

不過在把hash用ajax發(fā)出去之前要先進(jìn)行一些必要的非空驗(yàn)證

非空驗(yàn)證

主要是檢測郵箱是否為空、密碼是否為空、兩次輸入的密碼是否一致。

//發(fā)起請求之前驗(yàn)證是否為空
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("請您再次輸入確認(rèn)密碼")
    return false //精髓啊,不然沒用了
}
if (hash["password"] !== hash["password_confirmation"]) {
  $form.find("[name="password_confirmation"]").siblings(".errors").text("兩次輸入密碼不匹配")
  return false //精髓啊,不然沒用了
}

如果忘記寫return的話,即使你為空了還是會直接越過這一步檢測,去發(fā)起ajax請求的,所以一定不要忘了寫上return false.

如果僅僅這么寫的話會有一個(gè)bug。當(dāng)出現(xiàn)錯(cuò)誤提示后,你把信息填對了,錯(cuò)誤信息依然顯示,這顯然是不合理的。應(yīng)該填入信息后,錯(cuò)誤信息就消失的。

 $form.find(".errors").each((index, span) => {
     $(span).text("")
 }) 

使用上述的jq代碼來解決這個(gè)bug即可。

非空驗(yàn)證完了之后,意味著瀏覽器收集用戶數(shù)據(jù)的工作完成了,可以把hash發(fā)到服務(wù)器端了,接下來就是ajax請求了。

使用ajax提交數(shù)據(jù)
$.post("/sign_up", hash)
.then((response) => {
  //成功了就打印這個(gè)  
  console.log(response)
},
() => {
  //錯(cuò)誤了打印這個(gè)
})
服務(wù)器端解析formData

因?yàn)閒ormData是一段一段上傳的(具體原因略復(fù)雜,可以取極限法,如果formdata很多,不可能一下子上傳過來),自己不會寫,就去搜索代碼片段解析formdata

google: node get post data

把獲得的代碼封裝成了一個(gè)函數(shù)

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的解構(gòu)賦值
  }
  ...

當(dāng)服務(wù)器端接收到了所有的formdata數(shù)據(jù)后,其實(shí)是一串形如email=1&password=2&password_confirmation=3

的字符串,所以我們考慮使用&字符分割成數(shù)組。

得到一個(gè)形如["email=1", "password=2", "confirmation=3"]的數(shù)組之后,我們?yōu)榱说玫?b>string = "email=1"這種形式的,開始遍歷數(shù)組,把數(shù)組的每個(gè)元素按照=分割,得到 [email, 1]

用第二小節(jié)提供的hash+[]方法,處理成hash

服務(wù)器端簡單的校驗(yàn)

既然服務(wù)器端已經(jīng)獲得了formdata了,那么應(yīng)該進(jìn)行一下簡單的校驗(yàn),比如郵箱的格式,沒有問題了就把數(shù)據(jù)存到數(shù)據(jù)庫里面。(目前校驗(yàn)水平很入門,沒有涉及到完備的注冊校驗(yàn)功能)

校驗(yàn)前的準(zhǔn)備工作

上一節(jié)我們把formdata完美的封裝到了hash里面,為了校驗(yàn)我們要把hash再拆開一個(gè)一個(gè)的看

或許這么做是最直接的

let email = hash["emai"]
let password = hash["password"]
let password_confirmation = hash["password_confirmation"]

不過ES6提供了一種解構(gòu)賦值的語法糖,很甜很貼心……

let {email, password, password_confirmation} = hash
由@編碼引發(fā)的bug

好了,我們這一步就先看看郵箱格式是否正確。

我是菜鳥級校驗(yàn)郵箱,看到了郵箱的獨(dú)特標(biāo)志---@,最起碼有這個(gè)標(biāo)志才叫郵箱吧,也就是說沒有這個(gè)標(biāo)志,我就可以認(rèn)為郵箱格式不對啊,翻譯成代碼就是

if (email.indexOf("@") === -1) {
  response.statusCode = 400
  response.write("email is bad") //單引號只是為了標(biāo)記這是一個(gè)字符串
} 

很好,目前來說,事情的發(fā)展都很正常,直到一個(gè)bug的到來。

一個(gè)合法的郵箱,卻進(jìn)入了非法郵箱處理的代碼片段里面……

毫無疑問,郵箱是合法的,代碼也是合理的,那么出問題的必然是我,某個(gè)地方的理解有問題。

找bug,把可能出錯(cuò)的代碼片段分成幾個(gè)區(qū)間,打log.

console.log(email.indexOf("@"))
console.log(email)

沒錯(cuò),email這個(gè)字符串的@索引真的是-1,可是我的郵箱寫的明明有@啊。

為啥呢,接著又打印出了email的內(nèi)容,終于真相大白了,email字符串里面真的沒有@

卻發(fā)現(xiàn)了一串你沒想到的%40,(⊙v⊙)嗯,沒錯(cuò)了,這就是我認(rèn)為的那個(gè)@的另一個(gè)形態(tài)。

我在瀏覽器看到的只是瀏覽器想讓我看到的東西而已,既然已經(jīng)被瀏覽器處理了,那到了服務(wù)器端自然無法處理。

那這個(gè)%40哪來的呢

Google走起,在w3schools的HTML URL Encoding Reference找到了解釋(不是國內(nèi)的w3school……)

URL encoding converts characters into a format that can be transmitted over the Internet.

URL編碼把字符轉(zhuǎn)化成了一種可以在互聯(lián)網(wǎng)上傳播的格式,也就是說,我在網(wǎng)頁上看到的字符是被URL編碼處理的結(jié)果。

那接下來就去搞定什么是URL編碼

搞定這個(gè)之前,文檔先要讓你明白啥是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服務(wù)器請求頁面。 該網(wǎng)址是網(wǎng)頁的地址,例如:https://www.w3schools.com。

復(fù)習(xí)一下URL的組成6部分:

https://www.baidu.com/s?wd=he... 通過這個(gè)你就可以訪問到一個(gè) "唯一的" 網(wǎng)址

名字 作用
https: 協(xié)議
www.baidu.com 域名
/s 路徑
wd=hello&rsv_spt=1 查詢參數(shù)
#5 錨點(diǎn)
端口 默認(rèn)80

復(fù)習(xí)完了URL,繼續(xù)搞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.

URL只能用ASCII編碼在互聯(lián)網(wǎng)之間發(fā)送。

既然URL通常包括ASCII字符編碼集之外的字符(很明顯嘛,ASCII碼表太少),所以URL必須轉(zhuǎn)化成有效的ASCII格式。

這是重點(diǎn),URL編碼使用%后面緊跟著兩個(gè)16進(jìn)制數(shù)字的編碼格式來代替不安全的ASCII碼表

URL不能包括空格。所以URL編碼通常使用+號或者20%來代替空格。

繼續(xù)往下翻,找到了%40。

所以要把value的值解碼回去

hash[key] = decodeURIComponent(value)

decodeURIComponent() 方法用于解碼由 encodeURIComponent 方法或者其它類似方法編碼的部分統(tǒng)一資源標(biāo)識符(URI)。畢竟URL屬于URI。

錯(cuò)誤信息的提示方法

如果有了錯(cuò),需要提示用戶錯(cuò)了,后端寫的代碼,用戶不一定看的懂,需要前端潤色一下使用戶看懂,或者前端和后端溝通一下,maybe后端脾氣不好,前端也是暴脾氣,所以應(yīng)該選擇一個(gè)前后端都要用的東西做橋梁,很明顯JSON是完美的候選人。

if (email.indexOf("@") === -1) {
  response.statusCode = 400
  response.setHeader("Content-Type", "application/json;charset=utf-8") //直接告訴瀏覽器我是json
  response.write(`
    {
      "errors": {
      "email": "invalid"
      }
    }
  `)
}

這就合理多了,后臺只管寫個(gè)json給前臺看,其他不管了,前臺翻譯一下給用戶看嘍~

那么前臺如何獲得這個(gè)json

$.post("/sign_up", hash)
.then((response) => {
  //成功了就打印這個(gè)  
  console.log(response)
},
(request, b, c) => {
   console.log(request)
   console.log(b)
   console.log(c)
})

忘記了錯(cuò)誤函數(shù)里面的參數(shù)是啥了,那就都打印出來看看。

可以看到,如果沒用JSON的話,request對象里面有一個(gè)后端寫的responseText屬性可以利用。

設(shè)置了Content-Type:application/json;charset=utf-8之后,可以利用多出來的responseJSON屬性,獲得json的內(nèi)容啊。

最終失敗函數(shù)里面寫

(request) => {
  let {errors} = request.responseJSON    
  if (errors.email && errors.email === "invalid") {
    $form.find("[name="email"]").siblings(".errors").text("您輸入的郵箱錯(cuò)啦")
  }
}
校驗(yàn)郵箱是否已經(jīng)存在了
var users = fs.readFileSync("./db/users", "utf8")
try {
  users = JSON.parse(users) //[] JSON也支持?jǐn)?shù)組
} 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"
      }
    }
  `)
} 

本文并沒有使用真正意義上的數(shù)據(jù)庫,只是使用了簡單的db文件做數(shù)據(jù)庫,其實(shí)就是存的數(shù)組,也就是users其實(shí)就是數(shù)組[]。

之所以使用了try{}catch(){},是因?yàn)橐坏┏隋e(cuò),可以將其初始化為空數(shù)組,后續(xù)代碼可以繼續(xù)執(zhí)行,可能并不嚴(yán)謹(jǐn),不過本文是側(cè)重了解注冊的思路的。

同樣的,如果郵箱已經(jīng)存在了,就提示用戶

if (errors.email && errors.email === "inUse") {
    $form.find("[name="email"]").siblings(".errors").text("這個(gè)郵箱已被注冊啦")
}

后端校驗(yàn)必須很嚴(yán)格,因?yàn)榭梢酝ㄟ^curl越過前端的校驗(yàn)。

把信息寫入數(shù)據(jù)庫

沒有錯(cuò)誤之后,就可以把信息寫到數(shù)據(jù)庫里面啦

 users.push({email: email, password: password})//是個(gè)對象啊
 var usersString = JSON.stringify(users)
 fs.writeFileSync("./db/users", usersString)
 response.statusCode = 200

users實(shí)現(xiàn)是個(gè)對象,而對象是內(nèi)存里面的東西,數(shù)據(jù)庫里面應(yīng)該存儲的是字符串,所以用了JSON.stringify(users)

好啦,上篇注冊篇結(jié)束啦,下篇講一講如何登錄以及Cookie登場

相關(guān)代碼見sign_up.html

server.js

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107346.html

相關(guān)文章

  • 一塊餅干(Cookie)故事-下篇

    摘要:例如用戶去去買點(diǎn)東西,添加了一個(gè)熱水壺一部小米手機(jī)到購物車?yán)锩?,那么服?wù)器端可以改寫你上面的使之具體化,表示你購物車?yán)锩尜I了倆東西。一張圖總結(jié)注冊登錄的過程接下來可以去搞一搞其他的,像什么哇代碼鏈接 上篇介紹了注冊的基本流程,下篇簡單的講講登錄的流程以及Cookie的出現(xiàn) 實(shí)現(xiàn)登錄的小功能 當(dāng)你在瀏覽器的輸入框里輸入localhost:8080/sign_in的時(shí)候,會發(fā)起GET請求,...

    jayzou 評論0 收藏0
  • 一塊餅干(Cookie)故事-下篇

    摘要:例如用戶去去買點(diǎn)東西,添加了一個(gè)熱水壺一部小米手機(jī)到購物車?yán)锩?,那么服?wù)器端可以改寫你上面的使之具體化,表示你購物車?yán)锩尜I了倆東西。一張圖總結(jié)注冊登錄的過程接下來可以去搞一搞其他的,像什么哇代碼鏈接 上篇介紹了注冊的基本流程,下篇簡單的講講登錄的流程以及Cookie的出現(xiàn) 實(shí)現(xiàn)登錄的小功能 當(dāng)你在瀏覽器的輸入框里輸入localhost:8080/sign_in的時(shí)候,會發(fā)起GET請求,...

    lvzishen 評論0 收藏0
  • cookie餅干

    摘要:服務(wù)器給客戶端們頒發(fā)一個(gè)通行證,無論誰訪問都必須攜帶自己通行證,這樣服務(wù)器就能從通行證上確認(rèn)客戶身份了。瀏覽器根據(jù)是否設(shè)置的過期時(shí)間判斷該是會話還是永久,并將存儲在不同的位置。 服務(wù)端存放在客戶端的一段數(shù)據(jù)。這段數(shù)據(jù)在客戶端每次進(jìn)行http請求時(shí)會自動(dòng)加在http請求報(bào)文中的header上;服務(wù)端在響應(yīng)時(shí),可以對cookie進(jìn)行設(shè)置,并將cookie加入到http響應(yīng)報(bào)文header中...

    paulquei 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<