task44 Cookie与登录注册

请预习 Cookie、Session、Cache-Control 等 HTTP 知识

  • https://zh.wikipedia.org/wiki/Cookie
  • https://zhuanlan.zhihu.com/p/22396872?refer=study-fe
  • Session 维基百科:https://zh.wikipedia.org/wiki/%E4%BC%9A%E8%AF%9D_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)
  • Cache-Control

课上的代码:https://github.com/FrankFang/sign-in-demo

要点:

Cookie 的特点

  1. 服务器通过 Set-Cookie 响应头设置 Cookie
  2. 浏览器得到 Cookie 之后,每次请求都要带上 Cookie
  3. 服务器读取 Cookie 就知道登录用户的信息(email)

问题

  1. 我在 Chrome 登录了得到 Cookie,用 Safari 访问,Safari 会带上 Cookie 吗
    no
  2. Cookie 存在哪
    Windows 存在 C 盘的一个文件里
  3. Cookie会被用户篡改吗?
    可以,下节课会讲 Session 来解决这个问题,防止用户篡改
  4. Cookie 有效期吗?
    默认有效期20分钟左右,不同浏览器策略不同
    后端可以强制设置有效期,具体语法看 MDN
  5. Cookie 遵守同源策略吗?
    也有,不过跟 AJAX 的同源策略稍微有些不同。
    当请求 qq.com 下的资源时,浏览器会默认带上 qq.com 对应的 Cookie,不会带上 baidu.com 对应的 Cookie
    当请求 v.qq.com 下的资源时,浏览器不仅会带上 v.qq.com 的Cookie,还会带上 qq.com 的 Cookie
    另外 Cookie 还可以根据路径做限制,请自行了解,这个功能用得比较少。

1. 复习HTTP请求响应相关初级知识

这里的cookie、cache-control指的是响应头中的


task44 Cookie与登录注册_第1张图片
响应头.png

task44 Cookie与登录注册_第2张图片
image.png
task44 Cookie与登录注册_第3张图片
http请求和响应.png
task44 Cookie与登录注册_第4张图片
js发请求.png
  • js发请求
//js发请求(使用XMLHttpRequest)
var request = new XMLHttpRequest()
request.open('get','/xxx')  //配置request(get请求)
request.send()
//request.open('post','/xxx')  //配置request(post请求)
//request.send('a=1&b=2')
request.onreadystatechange=function(){
  if(request.readyState===4){
    console.log('请求响应都完成了')
    if(request.status >= 200 && request.status<300 ){
      console.log('请求成功')
    }
  }
}
  • Node.js接收请求并响应


    task44 Cookie与登录注册_第5张图片
    image.png
// 后端代码
if(path==='/xxx'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/json;charset=utf-8')
    response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')
    response.write(`
    {
      "note":{
        "to": "小谷",
        "from": "方方",
        "heading": "打招呼",
        "content": "hi"
      }
    }
    `)
    response.end()
}

2. 实现注册登录的功能

task44 Cookie与登录注册_第6张图片
注册页面

task44 Cookie与登录注册_第7张图片
客户端代码sign_up.html

hash数据.png

task44 Cookie与登录注册_第8张图片
服务端代码server.js
task44 Cookie与登录注册_第9张图片
客户端请求代码

promise????
此时发送post请求,服务端会返回什么结果?
——选B 一串html

task44 Cookie与登录注册_第10张图片
服务端代码server.js更改

服务端代码更改如上图,此时发送post请求,服务端会返回什么结果?
——选A 404

那么Node.js怎么读取post请求的数据?然后做相应的处理呢?


google(node http get post data)

task44 Cookie与登录注册_第11张图片
获取并打印请求体.png

获取用户请求的第四部分:
有点复杂,因为请求体是一段一段上传的,不是一下子上传的,所以要监听data事件,当监听到end的时候,将之前的数据接收到的数据都连接起来,获取完整的请求数据。

打印的请求体打印在服务端的控制台


task44 Cookie与登录注册_第12张图片
控制台打印请求体
使用promise封装一个读取请求body的方法readBody
task44 Cookie与登录注册_第13张图片
定义readBody
task44 Cookie与登录注册_第14张图片
使用readBody
  • 服务端解析请求体
//服务端解析请求体
把字符串格式的:email=1&password=2&password_confirmation=3
解析成hash格式的:{email:'1',password:'2',password_confirmation:'3'}
task44 Cookie与登录注册_第15张图片
服务端解析请求体.png
//ES5的写法
let email=hash[email]
let password=hash[password]
let password_confirmation=hash[password_confirmation]
//ES6的写法
let {email,password,password_confirmation}=hash  //ES6的写法

再加上客户端和服务端的数据验证、提示等
详见 课上的代码:https://github.com/FrankFang/sign-in-demo

//服务端代码
  }else if(path === '/sign_up' && method === 'POST'){
    readBody(request).then((body)=>{
      let strings = body.split('&') // ['email=1', 'password=2', 'password_confirmation=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] =value // hash['email'] = '1'
      })
      let {email, password, password_confirmation} = hash
      if(email.indexOf('@') === -1){//校验邮箱格式
        response.statusCode = 400
        response.setHeader('Content-Type', 'application/json;charset=utf-8')
        response.write(`{
          "errors": {
            "email": "invalid"
          }
        }`)
      }else if(password !== password_confirmation){//校验密码和确认密码是否一致
        response.statusCode = 400
        response.write('password not match')
      }else{//通过校验,返回200,注册成功
        response.statusCode = 200
        response.write('success sign up')
      }
      response.end()
    })
  }
//客户端代码
let $form = $('#signUpForm')
$form.on('submit', (e)=>{
  e.preventDefault()
  let hash = {}
  let need = ['email', 'password', 'password_confirmation']
  need.forEach((name)=>{
    let value = $form.find(`[name=${name}]`).val()
    hash[name] = value
  })
  $form.find('.error').each((index, span)=>{
    $(span).text('')
  })
  //校验各个字段非空,为空的话显示对应的提示信息并return
  if(hash['email'] === ''){
    $form.find('[name="email"]').siblings('.error')
      .text('填邮箱呀同学')
    return
  }
  if(hash['password'] === ''){
    $form.find('[name="password"]').siblings('.error')
      .text('填密码呀同学')
    return
  }
  if(hash['password_confirmation'] === ''){
    $form.find('[name="password_confirmation"]').siblings('.error')
      .text('确认密码呀同学')
    return
  }
  //校验密码和确认密码是否一致
  if(hash['password'] !== hash['password_confirmation']){
    $form.find('[name="password_confirmation"]').siblings('.error')
      .text('密码不匹配')
    return
  }
  $.post('/sign_up', hash)  
    .then((response)=>{
      console.log(response)
    }, (request)=>{
      let {errors} = request.responseJSON
      if(errors.email && errors.email === 'invalid'){
        $form.find('[name="email"]').siblings('.error')
          .text('邮箱格式错误')
      }
    })
})

这些校验前后端都要做!!!不能只是前端做,后端也要做的
因为可以通过curl不通过前端的js直接就请求到后端,所以后端一定要做相应的校验!!!


3. Cookie

这里有个问题,就是邮箱里面的@符号,在http请求中会变成%40
你以为有@,其实实际上没有@

task44 Cookie与登录注册_第16张图片
服务端server.js打印email字段

task44 Cookie与登录注册_第17张图片
服务端控制台显示email字段

不做处理的话,会一直报邮箱格式错误。怎么处理呢?
—— decodeURIComponent : 将已编码 URI 中所有能识别的转义序列转换成原字符。

task44 Cookie与登录注册_第18张图片
decodeURIComponent
当服务器发现邮箱、密码之类的都格式没问题了之后,需要做什么?
  • 创建文件db/users 用来存用户数据,当做数据库
  • 注册的时候验证没问题就把邮箱和密码存到数据库中
  • 新增users数据的时候需要考虑这个用户是否已经存在
  • 数据库中不应该存用户的明文密码,这样不安全,应该存加密后的密码,下次登录的时候将用户传过来的明文密码加密后和数据库中的密文密码比对,就可以判断密码是否正确了
  • 加一个登录页面
//注册接口服务端
//邮箱密码什么的都验证没问题后
}else{
  var users = fs.readFileSync('./db/users', 'utf8')
  try{
    users = JSON.parse(users) // []
  }catch(exception){
    users = []
  }
  let inUse = false
  for(let i=0; i
添加登录页面
task44 Cookie与登录注册_第19张图片
服务端代码

task44 Cookie与登录注册_第20张图片
登录页面sign_in.html
  • 服务端代码处理登录
//server.js
//sign_in的get请求,响应登录页面(html)
}else if(path==='/sign_in' && method === 'GET'){
  let string = fs.readFileSync('./sign_in.html', 'utf8')
  response.statusCode = 200
  response.setHeader('Content-Type', 'text/html;charset=utf-8')
  response.write(string)
  response.end()
}else if(path==='/sign_in' && method === 'POST'){
  readBody(request).then((body)=>{
    let strings = body.split('&') // ['email=1', 'password=2', 'password_confirmation=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} = hash
    var users = fs.readFileSync('./db/users', 'utf8')
    try{
      users = JSON.parse(users) // []
    }catch(exception){
      users = []
    }
    let found
    for(let i=0;i
  • 客户端代码-发送登录post请求
//sign_in.html
//发送sign_in的post请求,提交登录数据
$.post('/sign_in', hash)  
.then((response)=>{
  //登录成功,进入首页
  window.location.href = '/'
}, (request)=>{
  alert('邮箱与密码不匹配')
})

现在有一个问题就是,如果不通过登录页面,直接输入首页的url也可以进入首页。这样不是我们想要的效果,我们希望登录用户才可以进入首页,同时首页显示登录用户信息,这就要引入cookie

if(found){
  response.setHeader('Set-Cookie', `sign_in_email=${email}`) //!!!!加这一句
  response.statusCode = 200
}
  • 响应头多返回了个Set-Cookie↓


    task44 Cookie与登录注册_第21张图片
    响应头.png
  • 后面同源的请求头也就默认多了个cookie


    task44 Cookie与登录注册_第22张图片
    请求头.png

Cookie的特点

  1. 服务器通过Set-Cookie响应头设置Cookie
  2. 浏览器得到Cookie之后,每次请求都要带上Cookie(同源下?)
  3. 服务器读取请求头的Cookie就知道登录用户的信息(email)

问题

  1. 我在 Chrome 登录了得到 Cookie,用 Safari 访问,Safari 会带上 Cookie 吗
    no
  2. Cookie 存在哪
    Windows 存在 C 盘的一个文件里
  3. Cookie会被用户篡改吗?
    可以,下节课会讲 Session 来解决这个问题,防止用户篡改
  4. Cookie 有有效期吗?
    默认有效期20分钟左右,不同浏览器策略不同
    后端可以强制设置有效期,具体语法看 MDN


    task44 Cookie与登录注册_第23张图片
    image.png
  5. Cookie 遵守同源策略吗?
    也有,不过跟 AJAX 的同源策略稍微有些不同。
    当请求 qq.com 下的资源时,浏览器会默认带上 qq.com 对应的 Cookie,不会带上 baidu.com 对应的 Cookie
    当请求 v.qq.com 下的资源时,浏览器不仅会带上 v.qq.com 的Cookie,还会带上 qq.com 的 Cookie
    另外 Cookie 还可以根据路径做限制,请自行了解,这个功能用得比较少。
如何在首页显示登录用户信息?
  • nodejs read cookie


    image.png

console.log(request.headers.cookie)

//server.js
//服务端读取cookie
//在首页显示登录用户的信息(密码)
if(path === '/'){
  let string = fs.readFileSync('./index.html', 'utf8')
  let cookies =  request.headers.cookie.split('; ') // ['[email protected]', 'a=1', 'b=2']
  let hash = {}
  for(let i =0;i
task44 Cookie与登录注册_第24张图片
首页html.png

代码细节不用那么清楚,主要要搞清楚流程

你可能感兴趣的:(task44 Cookie与登录注册)