一块小饼干(Cookie)的故事-上篇

cookie 假如非要用汉语邃晓的话应当是 一段小型文本文件,由网景的创始人之一的
卢 蒙特利在93年发现。

上篇是熟习一下注册的大抵流程,下篇熟习登录流程以及真正的Cookie

完成基础的注册功用

我们翻开网站,阅读网站,最常见的两个操纵就是注册以及登录,所以有必要探究一下这两个功用怎样完成的。

当地模仿,当输入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)

好啦,上篇注册篇完毕啦,下篇讲一讲怎样登录以及Cookie上台

相干代码见sign_up.html

server.js

    原文作者:codevvvv9
    原文地址: https://segmentfault.com/a/1190000013231817
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞