美文网首页
注册登录 与 Cookie

注册登录 与 Cookie

作者: lyp82nkl | 来源:发表于2019-06-27 23:26 被阅读0次

    实现基本的注册功能

    本地模拟,当输入localhost:8080/sign_up的时候,浏览器发起get请求,服务器给你响应sign_up.html
    node代码:

    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()
     }
    

    获得用户的数据

    既然是注册的需求,那么首要关注的点就是--用户的注册信息如何获得呢?

    • 选择合理的数据结构存储数据是很重要的。

    • 每个input的name可以使用数组存储

    • input的value应该使用hash,也就是对象来存储。

    • 上述的套路会一直用下去,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
    })
    

    添加验证

    //当出现错误提示后,若之后将信息填对了,错误信息消失。
    $form.find('.errors').each((index, span) => {
        $(span).text('')
     }) 
    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_confirmationl'] === '') {
        $form.find('[name="password_confirmation"]').siblings('.error')
            .text('确认密码')
        return
    }
    if (hash['password'] !== hash['password_confirmation']) {
        $form.find('[name="password_confirmation"]').siblings('.error')
            .text('密码不匹配')
        return
    }
    

    验证完了之后,意味着浏览器收集用户数据的工作完成了,可以把hash发到服务器端了,接下来就是ajax请求了。
    ajax:

    $.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('邮箱格式错误')
    
            //订协议
            //http 协议
            //前后端撕逼协议
        }
    })
    

    服务器端解析formData

    为了便于对From Data这段代码的理解,将它封装成一个函数让它返回Promise(因为Form Data里面的数据是一段段上传的,所以需要时间,所以是一个异步的操作,而且需要对它进行监听,所以返回Promise)

    //想得到类似这种的 string == 'email=1'
    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)
            })
        })
    }
    

    node代码:

    if (path === '/sign_up' && method === 'POST') {//sign_up注册  
        readBody(request).then((body) => {
          let strings = body.split('&')//['email=1','password=2','possword_confirmation=3']
          let hash = {}
          strings.forEach((string) => {//遍历,假设第一次出现的是 'email=1'
            //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
    }
    
    • 当服务器端接收到了所有的formdata数据后,是一串形如email=1&password=2&password_confirmation=3

    的字符串,所以我们考虑使用&字符分割成数组。

    • 遍历数组,把数组的每个元素按照=分割,得到 [email, 1]
    • 用hash+[]方法,处理成hash
    错误信息的提示方法

    如果有了错,需要提示用户错了,使用JSON格式。

    if (email.indexOf('@') === -1) {
      response.statusCode = 400
      response.setHeader('Content-Type', 'application/json;charset=utf-8') //直接告诉浏览器我是json
      response.write(`
        {
          "errors": {
          "email": "invalid"
          }
        }
      `)
    }
    
    获取json
    (request) => {
        let { errors } = request.responseJSON
        if (errors.email && errors.email === 'invalid') {
            $form.find('[name="email"]').siblings('.error')
                .text('邮箱格式错误')
        }
    

    将填写的数据写入到users文件里

    else{
      //将文件users里面的内容赋值给users变量
      var users = fs.readFileSync('./db/users','utf8')
      try{
        //这里之所以JSON.parse()方法会报错是因为users变量里的内容读取的是文件users里的,
        //而users文件可能会被用户修改,比如改成var a=1...,而JSON.parse()方法只能将json格式的
        //字符串转成对象,所以对于不确定性这里会报错
        users = JSON.parse(users)
      }catch(exception){
        //将users变量的值替换为一个空的数组
        users = []
      }
      users.push({email: email, password: password})
      var usersString = JSON.stringify(users)
      //将userString变量里的内容写入文件users里(会将原来users里面的内容替换掉)
      //文件里只能写入字符串所以要将对象转为字符串存入文件
      fs.writeFileSync('./db/users', usersString)
      response.statusCode = 200
    }
    

    并没有使用真正意义上的数据库,只是创建一个db文件目录,里面有一个users文件做数据库,是一个空数组。


    try{}catch(){}

    try {
      f();
    } catch(e) {
     // 处理错误
    }
    上面代码中,如果函数f执行报错,就会进行catch代码块,接着对错误进行处理。
    catch代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。
    try {
     throw "出错了";
    } catch (e) {
     console.log(111);
    }console.log(222);// 111// 222
    上面代码中,try代码块抛出的错误,被catch代码块捕获后,程序会继续向下执行。
    

    如果再次点击注册按钮,在users里面就会多一个重复的对象;避免重复。

    //设置一个中间变量inUse
     let inUse = false;
     //遍历你users这个数组,
     for(let i = 0; i<users.length; i++){
       //如果users里面其中有一项的email等于你传入的email
       if(users[i].email === email){
         //就让inUse=true
         inUse = true;
         //然后退出循环
         break;
       }
     }
     //如果inUse是true响应一个400请求
     if(inUse){
       response.statusCode = 400
       response.write('email is exist')
     }else{
       users.push({email: email, password: password})
       var usersString = JSON.stringify(users)
       //将userString变量里的内容写入文件users里(会将原来users里面的内容替换掉)
       //文件里只能写入字符串所以要将对象转为字符串存入文件
       fs.writeFileSync('./db/users', usersString)
       response.statusCode = 200
     }
    

    通过Cookie实现登录

    Cookie的使用

    • 如果密码和邮箱与users文件里的一致,那么点击登录按钮请求成功跳到到首页
      问题1:用户可以不点登录直接访问首页的链接,并没有办法阻止用户访问首页。
      问题2:登录后能不能在首页显示出你的名字/邮箱
      需要在后台请求成功的时候加上一个cookie头:
    response.setHeader('Set-Cookie',`sign_in_email=${email}`)
    

    也就是说只要是set-Cookie了,之后相同域名下的所有文件的请求的请求头里面都会有一个cookie里面存储着set-Cookie里面的内容

    通过Cookie实现登录后显示密码

    node代码:

    else if(path === '/'){
      var string = fs.readFileSync('./index.html','utf8');
      //let cookies = request.headers.cookie.split(';')
      response.setHeader('Content-Type','text/html; charset=utf-8');
      let cookies = request.headers.cookie.split('; ')
      let hash = {}
      for(let i =0;i<cookies.length;i++){
        let parts = cookies[i].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)
      for(let i =0;i<users.length;i++){
        //如果users里面的email等于你cookie的email说明登录成功
        if(users[i].email === email){
          //成功就将index.html里的__password__字符替换为你users文件里的password
          string = string.replace('__password__',users[i].password)
        }else{
         //失败就替换为不知道
          string = string.replace('__password__','不知道')
        }
      }
      response.write(string)
      response.end()
    }
    

    html:

    <body>
        你的密码是:__password__
    </body>
    

    Cookie是什么

    1. Cookie 是浏览器访问服务器后,服务器传给浏览器的一段数据。

    2. 浏览器需要保存这段数据,不得轻易删除。

    3. 此后每次浏览器访问该服务器,都必须带上这段数据。

    Cookie 就是这么简单,这就是 Web 开发里 Cookie 的含义。

    一个具象化的例子
    比如你去一个公园,需要买票它的票可以两天内无限次的出入,你每次进园都带着你的票。这个Cookie就相当于一张长期的票,一次请求就相当于一次进园,如果你想一次请求后,下次还认识你,你只需要给一个setCookie(相当于公园卖给你一张票),下次请求的时候带上你的Cookie(就相当于下次进园带上票)

    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 还可以根据路径做限制,请自行了解,这个功能用得比较少。

    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。

    一张图总结注册登录的过程


    参考:简述 Cookie 是什么
    完整代码

    相关文章

      网友评论

          本文标题:注册登录 与 Cookie

          本文链接:https://www.haomeiwen.com/subject/ydsdcctx.html