首頁  >  文章  >  web前端  >  一起來學習Cookie

一起來學習Cookie

小云云
小云云原創
2018-02-09 14:35:461740瀏覽

本文主要和大家cookie一起來學習Cookie,如果非要用漢語理解cookie的話應該是 一段小型文本文件,由網景的創始人之一的盧 蒙特利在93年發明。希望本文能幫助大家。

實現基本的註冊功能

我們打開網站,瀏覽網站,最常見的兩個操作就是註冊以及登錄,所以有必要探索一下這兩個功能如何實現的。

本地模擬,當輸入localhost:8080/sign_up的時候,瀏覽器發起get請求,伺服器給你回應sign_up.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佈局的幾個小坑

在寫sign_up.html的時候,注意幾點css知識:

  1. 如果想讓你的登入頁面的body佔滿整個螢幕,隨著視窗的大小變化而變化的話,可以寫

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

當然了,實際上這麼寫就可以了

body{min-height: 100vh}
  1. label標籤是display: inline,不能設定寬度,行內元素則會根據行內內容自適應寬度,所以行內元素設定width是沒有效果的。改成inline-block就可以了

一起來學習Cookie

來取得使用者的資料

既然是註冊的需求,那麼我們首要關注的點就是--用戶的註冊資訊我們如何獲得呢

選擇合理的資料結構儲存資料是很重要的。

  1. 每個inputname可以使用陣列儲存

  2. inputvalue應該使用hash,也就是物件來儲存。

  3. 上述的套路會一直用下去,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裡面儲存的就是

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

到目前為止我們把使用者的資料封裝到了一個物件裡面了。

不過在把hash用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 //精髓啊,不然没用了
}
  • 如果忘記寫return的話,即使你為空了還是會直接越過這一步檢測,去發起ajax請求的,所以一定不要忘了寫上return false.

  • 如果只要這麼寫的話會有一個bug。當出現錯誤提示後,你把訊息填對了,錯誤訊息依然顯示,這顯然是不合理的。應該填入訊息後,錯誤訊息就消失的。

一起來學習Cookie

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

使用上述的jq程式碼來解決這個bug即可。

非空驗證完了之後,代表瀏覽器收集使用者資料的工作完成了,可以把hash發到伺服器端了,接下來就是ajax請求了。

使用ajax提交資料

$.post('/sign_up', hash)
.then((response) => {
  //成功了就打印这个  
  console.log(response)
},
() => {
  //错误了打印这个
})

伺服器端解析formData

因為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

由@編碼引發的bug

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

我是菜鸟级校验邮箱,看到了邮箱的独特标志---@,最起码有这个标志才叫邮箱吧,也就是说没有这个标志,我就可以认为邮箱格式不对啊,翻译成代码就是

if (email.indexOf('@') === -1) {
  response.statusCode = 400
  response.write('email is bad') //单引号只是为了标记这是一个字符串
}

很好,目前来说,事情的发展都很正常,直到一个bug的到来。

一起來學習Cookie

一个合法的邮箱,却进入了非法邮箱处理的代码片段里面……

一起來學習Cookie

毫无疑问,邮箱是合法的,代码也是合理的,那么出问题的必然是我,某个地方的理解有问题。

  • 找bug,把可能出错的代码片段分成几个区间,打log.

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

一起來學習Cookie

没错,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编码

搞定这个之前,文档先要让你明白啥是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.

  • URL只能用ASCII编码在互联网之间发送。

  • 既然URL通常包括ASCII字符编码集之外的字符(很明显嘛,ASCII码表太少),所以URL必须转化成有效的ASCII格式。

  • 这是重点,URL编码使用%后面紧跟着两个16进制数字的编码格式来代替不安全的ASCII码表

  • URL不能包括空格。所以URL编码通常使用+号或者20%来代替空格。

继续往下翻,找到了%40

一起來學習Cookie

所以要把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)
})

忘记了错误函数里面的参数是啥了,那就都打印出来看看。

一起來學習Cookie

可以看到,如果没用JSON的话,request对象里面有一个后端写的responseText属性可以利用。

一起來學習Cookie

设置了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越过前端的校验。

一起來學習Cookie

一起來學習Cookie


把信息写入数据库

没有错误之后,就可以把信息写到数据库里面啦

 users.push({email: email, password: password})//是个对象啊
 var usersString = JSON.stringify(users)
 fs.writeFileSync('./db/users', usersString)
 response.statusCode = 200

users实现是个对象,而对象是内存里面的东西,数据库里面应该存储的是字符串,所以用了JSON.stringify(users)

相关推荐:

JS前端缓存的实现方法及 Cookie的特点介绍

全面掌握Express cookie-parser中间件

JavaScript读取和写入cookie实例教程

以上是一起來學習Cookie的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn