一塊小餅乾(Cookie)的故事-下篇

吳少666發表於2019-03-01

上篇介紹了註冊的基本流程,下篇簡單的講講登入的流程以及Cookie的出現

實現登入的小功能

當你在瀏覽器的輸入框裡輸入localhost:8080/sign_in的時候,會發起GET請求,去訪問sign_in.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()
}
複製程式碼

CSS佈局與上篇的佈局基本一樣,略去不表~

比對使用者的資訊與資料庫裡面的資訊是否匹配

依然是上篇的套路,獲得使用者formdata後,分析資料,和資料庫裡面的比對

var users = fs.readFileSync(`./db/users`, `utf8`)
try {
	users = JSON.parse(users) //[] JSON也支援陣列
} catch (exception) {
	users = []
}

let found 
for (let i = 0; i < users.length; i++) {
if (users[i].email === email && users[i].password === password) {
  found = true
  break
  }
}
if (found) {
  response.setHeader(`Set-Cookie`, `sign_in_email=${email};HTTPOnly`)
  response.statusCode = 200
} else {
  response.statusCode = 401
}
複製程式碼

不同的是引入了一個header,也就是今天的主角–Cookie

其實這和平常上網的情形類似的,有時候我們訪問一些購物網站,並沒有登入,但是你在購物車裡面新增東西了,當你逛了以後再回來的時候,發現購物車裡面有你的記錄,幫你做這個事的也是cookie。

因為HTTP協議是無狀態的,即伺服器不知道使用者上一次做了什麼,這嚴重阻礙了互動式Web應用程式的實現。在典型的網上購物場景中,使用者瀏覽了幾個頁面,買了一盒餅乾和兩瓶飲料。最後結帳時,由於HTTP的無狀態性,不通過額外的手段,伺服器並不知道使用者到底買了什麼,所以Cookie就是用來繞開HTTP的無狀態性的“額外手段”之一。伺服器可以設定或讀取Cookies中包含資訊,藉此維護使用者跟伺服器會話中的狀態。

設定頭

可以看出,當你在sign_in發起GET請求並設定了Set-Cookie之後,其他的同源的頁面,又都會帶上Cookie,也就能保證同源的網頁向伺服器發起請求的時候,伺服器能夠明白,你己經是登入的使用者了,與那些沒有拿到cookie的頁面區別開來。

Cookie的入門

為什麼要在cookie裡面寫上HttpOnly呢,因為這個可以防止有些牛人使用JS修改Cookie的內容。

  • 如果不寫這個的話,可以使用js修改的
js修改cookie

寫了HttpOnly之後將無法修改

無法修改

_ga是啥

這個是Chrome的功能,用於分析cookie的

每一部分的作用詳見這裡

Cookie的特點

通過上述的例子,可以總結幾點重要的特點

  1. 伺服器通過 Set-Cookie 響應頭設定 Cookie
  2. 瀏覽器得到 Cookie 之後,每次請求都要帶上 Cookie
  3. 伺服器讀取 Cookie 就知道登入使用者的資訊(email)

當然了,還有幾個問題需要解答一下。

  1. Cookie 存在哪
    存在硬碟的一個檔案裡面
  2. Cookie會被使用者篡改嗎?
    可以,也就是說它並不安全的。
不安全
  1. Cookie 有效期嗎?

預設有效期20分鐘左右,不同瀏覽器策略不同
後端可以強制設定有效期

Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
複製程式碼

具體語法看 Set-Cookie

使用者登入後,首頁顯示不同

既然你成功登入,理應跳轉到首頁,並顯示相應的介面。

$.post(`/sign_in`, hash)
.then((response) => {
  window.location.href = `/`
}, 
(request) => {
  alert(`郵箱與密碼不匹配`)
  }
)
複製程式碼

然後首頁的資訊應該根據使用者資訊做出相應的變化

let cookies = request.headers.cookie.split(`; `) //[`email=..@..`, `a=1`]
let hash = {}
cookies.forEach((cookie) => {
  let parts = cookie.split(`=`)
  let key = parts[0]
  let value = parts[1]
  hash[key] = value
})
let email = hash.sign_in_email
let users = fs.readFileSync(`./db/users`, `utf8`)
users = JSON.parse(users)
let foundUser
for (let i = 0; i < users.length; i++) {
  if (users[i].email === email) {
    foundUser = users[i]
    break
  }
}
if (foundUser) {
  string = string.replace(`email`, foundUser.email)
} else {
  string = string.replace(`恭喜,email你已成功登入`, `沒有該使用者`)
}
複製程式碼

這裡的程式碼邏輯與上篇的基本一致,唯一的不同在於第一行程式碼

let cookies = request.headers.cookie.split(`; `) //[`email=..@..`, `a=1`]

為什麼用字元來分割呢,這是因為可以有多個cookie

多個cookie

Cookie的兩個作用

一般來說常見的作用有如下兩個:

  1. 識別使用者的身份。當使用者A去訪問localhost:8080的時候,伺服器會給A一個獨一無二的id=00A(這就是cookie),當使用者A訪問localhost:8080的其他網頁的時候,都會帶著那個獨一無二的id。當B使用者來訪問localhost:8080的時候,伺服器發現他沒有任何標識,也會給他一個獨一無二的id=00B,所以藉助cookie伺服器端就能夠分清楚誰是誰了。
  2. 記錄你的瀏覽歷史。最常見的需求就是你去逛購物網站,你新增到購物車裡面的東西過幾天一定會在,而不會憑空消失了。例如A使用者去taobao.com去買點東西,新增了一個熱水壺、一部小米手機到購物車裡面,那麼伺服器端可以改寫你上面的cookie使之具體化「id=00A; cart=A1,A2」,表示你購物車裡面買了倆東西。你過幾天想起來了,去購物車裡面看,熱水壺、小米手機還在裡面。瀏覽器並不會刪除你存到硬碟上的cookie。

一張圖總結註冊登入的過程

登入註冊的過程

接下來可以去搞一搞其他的,像什麼session LocalStorage……(@ο@) 哇~

程式碼連結sign_in.html

server.js

相關文章