nodejs开发博客笔记

218 阅读4分钟

目标
需求

技术方案

  • 数据存储
    • mysql存储博客数据
    • redis存储用户信息
  • 接口设计

知识点

  1. 开发接口
    • nodejs处理http请求
      • get请求
        const http =  require('http')
        const querystring = require('querystring')
        
        const server = http.createServer((req, res) => {
            console.log('method: ', req.method)  // GET
            const url = req.url
            console.log('url: ',url)
            req.query = querystring.parse(url.split('?')[1])
            console.log('query: ', req.query)
            
            res.end(
                JSON.stringify(req.query)
            )
        })
        server.listen(8000)
        console.log('OK')
        
        就可以在localhost看到hello world字样
      • post请求 需要用到postman调试
        const http = require('http');
        const querystring = require('querystring');
        
        const sever = http.createServer((req, res) => {
            if (method === 'POST') {
                // req 数据格式
                console.log('req Content-type: ', req.headers['Content-type'])
                // 接受数据
                let postData = '';
                req.on('data', chunk => {
                    postData += chunk.toString()
                })
                req.on('end', () => {
                    resData.postData = postData
                    res.end(
                        JSON.stringify(resData)
                    )
                })
            }
        });
        
        sever.listen(8000);
        console.log('ok')
        
        • get&post综合演示
        const http = require('http');
        const querystring = require('querystring');
        
        const sever = http.createServer((req, res) => {
            const method = req.method;
            const url = req.url;
            const path = url.split('?')[0];
            const query = querystring.parse(url.split('?')[1]);
        
            // 设置返回格式为 JSON
            res.setHeader('Content-type', 'application/json')
        
            // 返回的数据
            const resData = {
                method,     
                url,        
                path,
                query,      // url携带参数
            }
        
            // 返回
            if (method === 'GET') {
                res.end(
                    JSON.stringify(resData)
                )
            }
        
            if (method === 'POST') {
                let postData = '';
                req.on('data', chunk => {
                    postData += chunk.toString()
                })
                req.on('end', () => {
                    resData.postData = postData
                    res.end(
                        JSON.stringify(resData)
                    )
                })
            }
        });
        
        sever.listen(8000);
        console.log('ok')
        
      • 搭建开发环境
        使用nodemon监测文件变化,自动重启node;
        使用cross-env 设置环境变量
        • 路由
          • 开发路由
  2. 数据存储
    • 操作数据库
      使用Mysql Workbench
      • 建库
      • 建表
      • 表操作
        • 增删改查
      • nodejs操作mysql
      const mysql = require('mysql')
      
      // 创建链接对象
      const con = mysql.createConnection({
          host: 'localhost',
          user: 'root',
          password: '123456',
          port: '3306',
          database: 'myblog'
      })
      
      // 开始连接
      con.connect()
      
      // 执行 sql 语句
      const sql = `select * from users;`
      con.query(sql, (err, result) => {
          if (err) {
              console.error(err)
              return
          }
          console.log(result)
      })
      
      // 关闭连接
      con.end()
      
  3. 登录
    核心:登录校验 & 登录信息存储
    • 登录校验
      • cookie
        • 存储在浏览器的一段字符串(最大5kb)
        • 跨域不共享
        • 格式如:k1=v1;k2=v2;因此可以存储结构化数据
        • 每次发送http请求,会将请求域的cookie一起发送给server
        • server可以修改cookie并返回给浏览器
      • nodejs操作cookie
      1. 查看cookie req.headers.cookie
      2. 修改cookie
        // 操作cookie
        res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; 
        expires=${getCookieExpires()}`)
        
        其中path为cookie起作用的路径,httpOnly设置是防止通过js脚本读取到cookie信息
      3. 实现登录验证
        登录
        // 登录
        if (method === 'POST' && req.path === '/api/user/login') {
            // const { username, password } = req.query
            // 从数据库中查询对应数据(login函数)
            const result = login(username, password)
            return result.then(data => {
                if (data.username) {
                    // 操作cookie
                    res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; 
        expires=${getCookieExpires()}`)
                    return new SuccessModel()
                }
                return new ErrorModel('登录失败')
            })
        }
        
        登录验证(测试)
        // 登录验证测试
        if (method === 'GET' && req.path === '/api/user/login-test') {
            // 如果cookie中存在username 则登录成功
            if (req.cookie.username) {
                return Promise.resolve(
                    new SuccessModel({
                        usrename: req.cookie.username
                    })
                )
            }
            return Promise.resolve(
                new ErrorModel('尚未登录')
            )
        }
        
        (cookie补充)给cookie做限制
        1.对JS修改cookie做限制 httpOnly属性
        2.对cookie设置过期时间 expires属性
      • session

        • 为什么使用session:
          1. 为了解决cookie会暴露username很危险,所以将cookie存储userid,server端对应username,即用cookie存储userId,server端存储用户信息
          2. session运行在服务器端,当客户端第一次访问服务器时,可以将客户的登陆信息保存。
          3. 当客户访问其他界面时,可以判断客户的登陆状态,做出提示。
          4. 可以保存一些客户的常用信息,当客户端再次获取常用信息时,不必再从数据库中进行查询。
          5. session可以与redis或数据库等结合做持久化操作,当服务器挂掉时也不会导致某些客户信息(购物车)消失。
        • session的工作流程:
          1. 当浏览器访问服务器并发送第一次请求时,服务器端会创建一个session对象,生成一个类似于key,value的键值对,
          2. 然后将key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带key(cookie),找到对应的session(value)。
          3. 用户的信息都保存在session中。
        • 示例
          // session 数据
          const SESSION_DATA = {}
          
          // 解析session(未使用redis)
          let needSetCookie = false   // 设置是否需要设置cookie的制位符
          let userId = req.cookie.userid  // 获取当前userid
          if (userId) {
              if (!SESSION_DATA[userId]) {    // 有cookie,设置对应session
                  SESSION_DATA[userId] = {}
              }
          } else {
              needSetCookie = true
              userId = `${Date.now()}_${Math.random()}`
              SESSION_DATA[userId] = {}
          }
          req.session = SESSION_DATA[userId]
          
      • redis

        • 引入redis的原因:
        1. 目前session放在nodejs进程内存中,进程内存有限,访问量过大,内存暴增
        2. 正式上线运行是多进程,进程之间内存无法共享
        • nodejs中使用redis

          安装redis npm install redis

          const redis = require('redis')
          
          // 创建客户端
          const redisClient = redis.createClient(6379, '127.0.0.1')
          redisClient.on('error', err => {
              console.log(err)
          })
          
          // 测试
          redisClient.set('myname', 'zhangsan2', redis.print)
          redisClient.get('myname', (err, val) => {
              if(err) {
                  console.log(err)
                  return
              }
              console.log('val ', val)
              redisClient.quit()
          })
          
    • 登录信息存储
  4. 日志
  5. 安全