36·灵魂前端工程师养成-[前后分离]AJAX实战Cookie、Session

2022-09-26 17:31:05 浏览数 (1)

  • 动态服务器
  • 实现用户注册功能
  • 实现用户注册功能
  • 实现用户登录功能
  • Cookie介绍
  • 把cookie替换成user id
  • 使用session保存用户信息

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


动态服务器


静态服务器 VS 动态服务器

我们也可以说,静态网页和动态网页,还有静态请求,动态请求。

判断依据: 是否请求了数据库,没有请求数据库,就是静态服务器,请求了数据库就是动态服务器

但是数据库和前端没有啥关系,所以我们使用json文件模拟数据库。

首先,我们先创建一个项目,把上次的static-server复制一下即可。

使用vscode打开。

创建一个目录,db当数据库,里面创建一个user.json文件,当做是数据库中的表,然后往里写数据

代码语言:javascript复制
[
    {"id":1,"name":"zls","password":"123"},
    {"id":2,"name":"haoda","password":"124"},
    {"id":3,"name":"qls","password":"125"}
]

测试读取数据。

代码语言:javascript复制
const fs = require('fs')
// 读数据库
const userString = fs.readFileSync('./db/user.json').toString()
// 获取到的数据,必须要转换成数组
const userArray = JSON.parse(userString)

// 打印出两种数据.是不一样的,看起来差不多,其实差很多
console.log(userString)
console.log(userArray)

测试写数据库

代码语言:javascript复制
const user4 = {id:4,name:'drz',password:'126'}
userArray.push(user4)
const string = JSON.stringify(userArray)
fs.writeFileSync('./db/user.json',string)

这样就写进去了,所以格式略微有点变化。不过问题不大。

实现用户注册功能

创建一个注册页面

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>注册</title>
</head>
<body>
    <form action="">
        <div>
            <label>用户名<input type="text" name="name"></label>
        </div>
        <div>
            <label>密码<input type="password" name="password"></label>
        </div>
        <div>
            <button type="submit">注册</button>
        </div>
    </form>
</body>
</html>

引入jQuery

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>注册</title>
</head>
<body>
    <form id="registerForm">
        <div>
            <label>用户名<input type="text" name="name"></label>
        </div>
        <div>
            <label>密码<input type="password" name="password"></label>
        </div>
        <div>
            <button type="submit">注册</button>
        </div>
    </form>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <script>
        const $form = $('#registerForm')
        $form.on('submit',(e)=>{
            e.preventDefault()
            const name = $form.find('input[name=name]').val()
            const password = $form.find('input[name=password]').val()
            console.log(name)
            console.log(password)
            $.ajax({
                method:'POST',
                url:'/register',
                data: JSON.stringify({name,password})
            })
        })
    </script>
</body>
</html>

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>注册</title>
</head>
<body>
    <form id="registerForm">
        <div>
            <label>用户名<input type="text" name="name"></label>
        </div>
        <div>
            <label>密码<input type="password" name="password"></label>
        </div>
        <div>
            <button type="submit">注册</button>
        </div>
    </form>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <script>
        const $form = $('#registerForm')
        $form.on('submit',(e)=>{
            e.preventDefault()
            const name = $form.find('input[name=name]').val()
            const password = $form.find('input[name=password]').val()
            console.log(name)
            console.log(password)
            $.ajax({
                method:'POST',
                url:'/register',
                contentType: 'text/json; charset=UTF-8',
                data: JSON.stringify({name,password})
            })
        })
    </script>
</body>
</html>

实现用户注册功能

修改server.js,后端获取用户名和密码

代码语言:javascript复制
  if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html')
    response.end("很好")
  }

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)

  if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html')
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      console.log(array)
      response.end("很好")
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

获取到了,但是...是一堆乱码,emm...其实并不是乱码,是UTF-8字符集,我们给他合成字符串即可。

代码语言:javascript复制
const string = Buffer.concat(array).toString()
console.log(string)

把获取到的字符串,变成对象,然后打印出来看看。

代码语言:javascript复制
const obj = JSON.parse(string)
console.log(obj.name)
console.log(obj.password)

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)

  if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const lastUSer = userArray[userArray.length -1]
      const newUser = {
        // 如果最后一个用户存在,那么就是最后一个用户的id 1,不存在就是1
        id: lastUSer ? lastUSer.id   1: 1,
        name: obj.name,
        password: obj.password
      }
      userArray.push(newUser)
      fs.writeFileSync('./db/user.json',JSON.stringify(userArray))
      response.end()
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

注册完,立马写入。

然后我们来完善后续,注册成功,那么我们就可以跳转到登录页面了,但是emm...登录页面还没有,我们先把代码写出来,写完之后,创建一个sigin.html

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>注册</title>
</head>
<body>
    <form id="registerForm">
        <div>
            <label>用户名<input type="text" name="name"></label>
        </div>
        <div>
            <label>密码<input type="password" name="password"></label>
        </div>
        <div>
            <button type="submit">注册</button>
        </div>
    </form>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <script>
        const $form = $('#registerForm')
        $form.on('submit',(e)=>{
            e.preventDefault()
            const name = $form.find('input[name=name]').val()
            const password = $form.find('input[name=password]').val()
            console.log(name)
            console.log(password)
            $.ajax({
                method:'POST',
                url:'/register',
                contentType: 'text/json; charset=UTF-8',
                data: JSON.stringify({name,password})
            }).then(()=>{
                alert('注册成功')
                location.href = '/sigin.html'
            },()=>{})
        })
    </script>
</body>
</html>

实现用户登录功能

需求,我们需要做两个页面:

1.首页home.html,已经登录的用户可以看到自己的用户名 2.登录页sigin.html,让用户提交用户名和密码

home.html

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>
        你好,{{ user.name }}
    </p>
    <p>
        <a href="sigin.html">登录</a>
    </p>
</body>
</html>

写一个登录页

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
</head>
<body>
    <form id="siginForm">
        <div>
            <label>用户名<input type="text" name="name"></label>
        </div>
        <div>
            <label>密码<input type="password" name="password"></label>
        </div>
        <div>
            <button type="submit">登录</button>
        </div>
    </form>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <script>
        const $form = $('#siginForm')
        $form.on('submit',(e)=>{
            e.preventDefault()
            const name = $form.find('input[name=name]').val()
            const password = $form.find('input[name=password]').val()
            $.ajax({
                method:'POST',
                url:'/sigin',
                contentType: 'text/json; charset=UTF-8',
                data: JSON.stringify({name,password})
            }).then(()=>{
                alert('登录成功')
                location.href = '/home.html'
            },()=>{})
        })
    </script>
</body>
</html>

实现后端的逻辑

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)
  if(path === '/sigin' && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const user = userArray.find((user)=> user.name === obj.name && user.password === obj.password)
      if(user === undefined){
        response.statusCode = 400
        response.end('用户名密码不匹配')
      }else{
        response.statusCode = 200
        response.end()
      }
    })
  } else if(path === '/home.html'){
    response.end('home')
  } else if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const lastUSer = userArray[userArray.length -1]
      const newUser = {
        // 如果最后一个用户存在,那么就是最后一个用户的id 1,不存在就是1
        id: lastUSer ? lastUSer.id   1: 1,
        name: obj.name,
        password: obj.password
      }
      userArray.push(newUser)
      fs.writeFileSync('./db/user.json',JSON.stringify(userArray))
      response.end()
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

瞎写,登录失败返回400

正常写,200,单击完确定就会跳转到首页。

我们修改一下home的页面,显示登录状态。

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>
        {{ loginStatus }}
    </p>
    <p>
        <a href="sigin.html">登录</a>
    </p>
</body>
</html>

那么如何识别,用户是否登录过呢?因为我们在登录后,显示home页面,但是我们不登录,直接访问http://127.0.0.1:8888/home.html 也是一样呀。同样都能访问到home页面,和不需要登录有啥区别?

所以我们必须要识别 用户到底有没有登录,没有登录那么就去登录页面 ,登录过后,才能去home页面,直接访问home,直接跳转到登录页面。

Cookie介绍

定义: Cookie是服务器下发给浏览器的一段字符串,浏览器必须,保存这个Cookie(除非删除 用户),之后发起相同二级域名请求(任何请求)时,浏览器必须附上Cookie。

就相当于是一个令牌,登录成功就是皇上给你发了个令牌,但是只要进入京城,不管去哪里都要随身携带令牌,如果一旦令牌失效,对不起,再见,fire the hole...

再举个例子,公园的检票员,如何才能知道你能不能进呢?你是不是需要去买张票?买完票就相当于拿到了 Cookie,票=Cookie,有些公园里面有景区,进入景区或者xxx故居,还得再看看你的票,才能让你进,就是这个样子,所以只要你登录了,以后你不管访问哪个页面,都会带着Cookie去访问。

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)
  if(path === '/sigin' && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const user = userArray.find((user)=> user.name === obj.name && user.password === obj.password)
      if(user === undefined){
        response.statusCode = 400
        response.end('用户名密码不匹配')
      }else{
        response.statusCode = 200
        response.setHeader('Set-Cookie','logined=1')
        response.end()
      }
    })
  } else if(path === '/home.html'){
    response.end('home')
  } else if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const lastUSer = userArray[userArray.length -1]
      const newUser = {
        // 如果最后一个用户存在,那么就是最后一个用户的id 1,不存在就是1
        id: lastUSer ? lastUSer.id   1: 1,
        name: obj.name,
        password: obj.password
      }
      userArray.push(newUser)
      fs.writeFileSync('./db/user.json',JSON.stringify(userArray))
      response.end()
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

home页面获取Cookie

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)
  if(path === '/sigin' && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const user = userArray.find((user)=> user.name === obj.name && user.password === obj.password)
      if(user === undefined){
        response.statusCode = 400
        response.end('用户名密码不匹配')
      }else{
        response.statusCode = 200
        response.setHeader('Set-Cookie','logined=1')
        response.end()
      }
    })
  } else if(path === '/home.html'){
    const cookie = request.headers['cookie']
    if(cookie === 'logined=1'){
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      const string = homeHtml.replace('{{ loginStatus }}','已登录')
      response.write(string)
    } else{
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      const string = homeHtml.replace('{{ loginStatus }}','未登录')
      response.write(string)
    }
    response.end()
  } else if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const lastUSer = userArray[userArray.length -1]
      const newUser = {
        // 如果最后一个用户存在,那么就是最后一个用户的id 1,不存在就是1
        id: lastUSer ? lastUSer.id   1: 1,
        name: obj.name,
        password: obj.password
      }
      userArray.push(newUser)
      fs.writeFileSync('./db/user.json',JSON.stringify(userArray))
      response.end()
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie 设置cookie语法的网站,我们进去看看

一定要加上HttpOnly禁止前端操作cookie

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)
  if(path === '/sigin' && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const user = userArray.find((user)=> user.name === obj.name && user.password === obj.password)
      if(user === undefined){
        response.statusCode = 400
        response.end('用户名密码不匹配')
      }else{
        response.statusCode = 200
        response.setHeader('Set-Cookie','logined=1;HttpOnly')
        response.end()
      }
    })
  } else if(path === '/home.html'){
    const cookie = request.headers['cookie']
    if(cookie === 'logined=1'){
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      const string = homeHtml.replace('{{ loginStatus }}','已登录')
      response.write(string)
    } else{
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      const string = homeHtml.replace('{{ loginStatus }}','未登录')
      response.write(string)
    }
    response.end()
  } else if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const lastUSer = userArray[userArray.length -1]
      const newUser = {
        // 如果最后一个用户存在,那么就是最后一个用户的id 1,不存在就是1
        id: lastUSer ? lastUSer.id   1: 1,
        name: obj.name,
        password: obj.password
      }
      userArray.push(newUser)
      fs.writeFileSync('./db/user.json',JSON.stringify(userArray))
      response.end()
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

辣么问题又来了,home.html只是知道你登录了,但是怎么知道你登录的是谁呢? 所以我们要把cookie跟user id 绑定。

把cookie替换成user id

home.html

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>
        {{ user.name }}
        {{ loginStatus }}
    </p>
    <p>
        <a href="sigin.html">登录</a>
    </p>
</body>
</html>

server.js

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)
  if(path === '/sigin' && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const user = userArray.find((user)=> user.name === obj.name && user.password === obj.password)
      if(user === undefined){
        response.statusCode = 400
        response.end('用户名密码不匹配')
      }else{
        response.statusCode = 200
        response.setHeader('Set-Cookie',`user_id=${user.id};HttpOnly`)
        response.end()
      }
    })
  } else if(path === '/home.html'){
    const cookie = request.headers['cookie']
    let userId
    try {
      userId = cookie.split(';').filter(s => s.indexOf('user_id=')>=0)[0].split('=')[1]
    } catch (error) {}
    if(userId){
      const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
      const user = userArray.find(user => user.id.toString() === userId)
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      let string
      if(user){
        string = homeHtml.replace('{{ loginStatus }}','已登录')
          .replace('{{ user.name }}',user.name)
      }
      response.write(string)
    } else{
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      const string = homeHtml.replace('{{ loginStatus }}','未登录')
      .replace('{{ user.name }}','')
      response.write(string)
    }
    response.end()
  } else if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const lastUSer = userArray[userArray.length -1]
      const newUser = {
        // 如果最后一个用户存在,那么就是最后一个用户的id 1,不存在就是1
        id: lastUSer ? lastUSer.id   1: 1,
        name: obj.name,
        password: obj.password
      }
      userArray.push(newUser)
      fs.writeFileSync('./db/user.json',JSON.stringify(userArray))
      response.end()
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

但是,有一个大大大大大大大的BUG,就是用户可以篡改user id

我们改成2,然后刷新页面

卧槽,如果我知道MHT的QQ用户id岂不是我直接登录他的QQ号了?

使用session保存用户信息

为了修改大bug我们必须要使用session

其实,我们有两个思路

代码语言:javascript复制
## 思路一:加密
# 将user id加密发送给前端,后端 读取user id时解密,此法可行,但是有安全漏洞。
# 漏洞:加密后内容可无限期使用
# 解决办法:JWT(想知道嘛?想知道呀,后面再讲)

## 思路二:把信息隐藏在服务器
# 把用户信息放在服务器的某个[x]地方,可以是数据库,可以是文件,可以是redis,可以是memcache,可以是...
# 不管放在哪里,再给这个信息一个随机的id,把随机的id发送给浏览器,后端下次读取到id的时候,通过x[id]获取用户信息,x是什么?x就是我上面说的redis,memcache,MySQL,文件,等地方。
# 想想为什么,用户无法篡改id,因为id很长,且随机。
# 所以,这个x又被叫做session(会话)
# 以后我们还会做,会话保持

创建一个session文件

session.json

代码语言:javascript复制
{
    "123123123123213123123123":{"user_id":1}
}

代码原来的 user_id ,改成 session_id

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/
  const session  = JSON.parse(fs.readFileSync('./session.json').toString())
  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)
  if(path === '/sigin' && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const user = userArray.find((user)=> user.name === obj.name && user.password === obj.password)
      if(user === undefined){
        response.statusCode = 400
        response.end('用户名密码不匹配')
      }else{
        response.statusCode = 200
        const random = Math.random()
        session[random] = {user_id: user.id}
        fs.writeFileSync('./session.json',JSON.stringify(session))
        response.setHeader('Set-Cookie',`session_id=${random};HttpOnly`)
      }
      response.end()
    })
  } else if(path === '/home.html'){
    const cookie = request.headers['cookie']
    let sessionId
    try {
      sessionId = cookie.split(';').filter(s => s.indexOf('session_id=')>=0)[0].split('=')[1]
    } catch (error) {}
    if(sessionId && session[sessionId]){
      const userId = session[sessionId].user_id
      const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
      const user = userArray.find(user => user.id === userId)
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      let string = ''
      if(user){
        string = homeHtml.replace('{{ loginStatus }}','已登录')
          .replace('{{ user.name }}',user.name)
      }
      response.write(string)
    } else{
      const homeHtml = fs.readFileSync('./public/home.html').toString()
      const string = homeHtml.replace('{{ loginStatus }}','未登录')
      .replace('{{ user.name }}','')
      response.write(string)
    }
    response.end()
  } else if(path === "/register" && method === 'POST'){
    response.setHeader('Content-Type','text/html; charset=utf-8')
    const userArray = JSON.parse(fs.readFileSync('./db/user.json'))
    const array = []
    request.on('data',(chunk)=>{
      array.push(chunk)
    })
    request.on('end',()=>{
      const string = Buffer.concat(array).toString()
      const obj = JSON.parse(string)
      const lastUSer = userArray[userArray.length -1]
      const newUser = {
        // 如果最后一个用户存在,那么就是最后一个用户的id 1,不存在就是1
        id: lastUSer ? lastUSer.id   1: 1,
        name: obj.name,
        password: obj.password
      }
      userArray.push(newUser)
      fs.writeFileSync('./db/user.json',JSON.stringify(userArray))
      response.end()
    })
  }else{
    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

我们来篡改一下。。。

刷新页面,立马变成未登录。

0 人点赞