模拟注册登录+cookie

项目的源代码及使用方法请点击这里. 运行demo需要先安装node
这篇文章不会贴上全部代码, 只会说下思路. 具体实现还请到github库中看源码.

基本结构

index.html: 首页
sign_in.html: 登录页面
sign_up.html: 注册页面
server.js: 服务器
db/users: 模拟数据库, 实质上是一个数组, 每个数组项是一个对象, 表示一个用户

用户可以直接进入首页, 通过登录的方式进入首页. 通过登录的方式进入首页时设置了cookie, 此时可以再首页看到用户的邮箱.
用户注册的账号会存储在db/users文件中. 当用户以相同的邮箱注册时会提示用户已注册. 注册时也会验证邮箱的有效性和密码的一致性.
服务器主要实现路由操作. 当使用不同的路由时采取不同的动作.

首页index.html

由于是模拟登录, 因此首页只会展示用户的邮箱(通过cookie). 若没有cookie, 则不显示邮箱

<body>
    <h1>欢迎 __user__ 登录</h1>
</body>

__user__是一个占位符, server.js程序在后台运行. 当用户登录时, server.js设置__user__为用户邮箱

string = string.replace('__user__', foundUser.email) //foundUser为登录用户

注册页sign_up.html

我们在进行注册的时候需要输入密码, 而且还要确认这个密码. 因此结构如下:

        <form action="" id="signUpForm">
            <div class="row">
                <label for="">邮箱</label>
                <input type="text" name="email">
                <span class="message"></span><!--错误处理占位-->
            </div>
            <div class="row">
                <label for="">密码</label>
                <input type="password" name="password">
                <span class="message"></span>
            </div>
            <div class="row">
                <label for="">确认密码</label>
                <input type="password" name="password_confirmation">
                <span class="message"></span>
            </div>
            <div class="row">
                <input type="submit" value="注册">
            </div>
        </form>

对于邮箱, 密码等我们需要进行检验, 比如:

  • 邮箱是否有效, 有@
  • 邮箱是否未注册.
  • 两次密码是否输入一致
  • 全部都是必填项.

若全部复合条件, 则使用post方法向服务器发送请求.

//假设已经引入jQuery库
$form = $('#signUpForm')
        $form.on('submit', function(e){
            e.preventDefault()
            let hash = {}
            let need = ['email', 'password', 'password_confirmation']
            need.forEach(function(name){
                let value = $form.find(`[name=${name}]`).val()
                hash[name] = value
            })
            $form.find('.message').each(function(index, span){
                $(span).text('')
            })
            if(hash['email'] === '') {
                $form.find('[name="email"]').siblings('.message').text("请填写邮箱")
                return 
            }
            if(hash['password'] === '') {
                $form.find('[name="password"]').siblings('.message').text("请填写密码")
                return 
            }
            if(hash['password_confirmation'] === '') {
                $form.find('[name="password_confirmation"]').siblings('.message').text("请填写密码")
                return 
            }
            if(hash["password"] !== hash['password_confirmation']) {
                $form.find('[name="password_confirmation"]').siblings('.message').text("密码不匹配")
                return 
            }
            $.post('/sign_up', hash)
            .then(function(response){
                let message = response
                console.log(message)
                if (message.email && message.email === 'successed') {
                    $form.find('[name="email"]').siblings('.message')
                        .text('注册成功')
                }
            }, (xhr)=>{
                console.log(xhr)
                //服务器端设置了application/json头
                let {message}=xhr.responseJSON
                console.log(message)
                if (message.email && message.email === 'invalid') {
                    $form.find('[name="email"]').siblings('.message')
                        .text('邮箱格式错误')
                } else if (message.email && message.email === 'used') {
                    $form.find('[name="email"]').siblings('.message')
                        .text('邮箱已被注册')
                }
            })
        })

$.post方法后面可以接Promise的方法来根据服务器返回的数据(JSON)显示结果

登录页sign_in.html

这个页面时登录页面, 因此只需要邮箱和密码就可以了

<form action="" id="signInForm">
    <div class="row">
         <label for="">邮箱</label>
         <input type="text" name="email">
         <span class="message"></span>
     </div>
     <div class="row">
         <label for="">密码</label>
         <input type="password" name="password">
         <span class="message"></span>
     </div>
     <div class="row">
         <input type="submit" value="登录">
     </div>
 </form>

当然还是需要通过server.js返回的数据进行验证:

  • 账户是否存在
  • 密码是否正确
  • 全部为必填项
//假设已经引入jQuery
$form = $('#signInForm')
        $form.on('submit', function(e){
            e.preventDefault()
            let hash = {}
            let need = ['email', 'password']
            need.forEach(function(name){
                let value = $form.find(`[name=${name}]`).val()
                hash[name] = value
            })
            $form.find('.message').each(function(index, span){
                $(span).text('')
            })
            if(hash['email'] === '') {
                $form.find('[name="email"]').siblings('.message').text("请填写邮箱")
                return 
            }
            if(hash['password'] === '') {
                $form.find('[name="password"]').siblings('.message').text("请填写密码")
                return 
            }
            $.post('/sign_in', hash)
            .then(function (response){
                window.location.href='/'
            }, ()=>{
                alert('邮箱或密码错误')
            })
        })

服务器server.js

server.js主要实现了以下路由

if (path === '/') {
    //返回index.html, 若是用户登录则获取已设置好的cookie
} else if (path === '/sign_up' && method === 'GET') {
    //返回注册页
} else if (path === '/sign_up' && method === 'POST') {
    //获取注册页的post请求体(用户注册信息), 根据请求体返回响应JSON数据
} else if (path === '/sign_in' && method === 'GET') {
    //返回登录页
} else if (path === '/sign_in' && method === 'POST') {
    //获取登录页的post请求体(用户登录信息), 根据请求体返回JSON数据, 且设置cookie
} 

因为请求体不是一次性返送的, 每次传给服务器的数据大小有要求, 因此我们需要服务器接收完整的请求体才能做出下一步动作. 在server.js中实现完整读取请求体的函数readBody.

function readBody(request) {
  return new Promise(function (resolve, reject){
    let body = [] //请求体
    request.on('data', function(chunk){
      console.log('服务器正在接收请求体')
      // 监听data事件
      body.push(chunk);
    }).on('end', function(){
      // 监听end事件, 当服务器接收POST请求中的全部数据触发
      console.log('服务器接收完毕请求体')
      body = Buffer.concat(body).toString();
      resolve(body)
    })
  })
}

我们已经知道server.js的大致架构. 比较重要的是两个处理, 一个是用户注册时的处理, 一个是用户登录时的处理.

用户注册

当用户进行注册时, sign_up.html首先会自己检测必填项是否已填写. 然后通过post方法将用户填入的邮箱和密码信息发送给server.js服务器. 服务器会一次进行以下工作:

  • 获取请求体(邮箱, 密码), 注意要解码
  • 邮箱检测(@符号)及密码一致性检验(即两次密码是否相同)
  • 遍历db/users文件, 检测是否未注册
  • 返回响应, 若已注册通知用户重新填写, 否则告诉用户注册成功

当注册成功时, 数据会写入db/users文件.
假设我们注册的是[email protected], 密码为:1. 那么我们就会在db/users文件中看到如下账号:

[{"email": "[email protected]", "password": "1"}] //注意users的内容是个数组, 每个数组项是对象, 代表一个账户

用户登录

假设用户已经注册好账户了, 在登录页sign_in.html输入邮箱([email protected])和密码(1). 点击登录会做一下事情:

  • 检查必填项
  • 向服务器发送响应
  • 遍历db/users文件, 检测是否存在用户
  • 返回响应, 若不存在则告诉用户错误, 否则先设置cookie再转向登录页index.html
  • index.html读取请求体中的cookie信息并显示出来

当直接进入首页index.html时, 不会显示cookie信息.

cookie

cookie上文中简单提到了. 用户登录时会设置cookie, 登录成功读取cookie值并显示.
当点击sign_in.html页面的登录按钮时, , server.js服务器会将设置cookie

response.setHeader('Set-Cookie', `sign_in_email=${email}`) //设置email的cookie

服务器将设置的cookie返回给浏览器, 因为邮箱及密码没有问题则再发送一次包含cookie的请求, 这次请求是告诉服务器我要进入登录页.
登录页会取出请求体中的cookie并显示.

let cookies = request.headers.cookie.split('; ')    //获取请求体中的cookie并分割
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//hash中存放的是key-value形式的cookie
 }
 //hash中存在登录账户的cookie
 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
    }
  }
 // 将占位符__user__换成cookie值. foundUser是登录账户的cookie
string = string.replace('__user__', foundUser.email)

当用户直接进入index.html页面而不是通过登录方式进入时, 服务器就不会设置cookie. 此时就不显示cookie, 给占位符一个统一的名称即可.

string = string.replace('__user__', '同学') 

猜你喜欢

转载自blog.csdn.net/helloyongwei/article/details/80543096
今日推荐