项目目录

配置常用中间件

  1. 常用中间件:

    • 解析请求体: express.json()、 express.urlencoded()
    • 日志输出: morgan()
    • 为客户端提供跨域资源请求 cors()
  2. 示例代码:

    const express = require('express')
    const morgan = require('morgan')
    const cors = require('cors')
    const router = require('./router')
    const errorHandler = require('./middleware/error-handler')
    
    // 数据库连接
    require('./model')
    
    const app = express()
    
    // 日志
    app.use(morgan('dev'))
    
    // 解析json 
    app.use(express.json())
    
    // 为客户端提供跨域资源请求
    // 会在请求头头中:Access-Control-Origin:*
    app.use(cors())
    
    const PORT = process.env.PORT || 3000
    
    // 挂载路由
    app.use('/api', router)
    
    // 挂载统一处理服务端错误中间件
    app.use(errorHandler())
    
    app.listen(PORT, () => {
      console.log(`Server is running at http://localhost:${PORT}`)
    })
    

路由设计

  1. 剥离每个模块的路由:(router/index.js)

    const express = require('express')
    const router = express.Router()
    
    // 用户相关路由
    router.use(require('./user'))
    
    // 用户资料相关路由
    router.use('/profiles', require('./profile'))
    
    // 文章相关路由
    router.use('/articles', require('./article'))
    
    // 标签相关路由
    router.use('/tags', require('./tag'))
    
    module.exports = router
    
  2. 用户相关路由:(router/user.js)

    const express = require('express')
    const userCtrl = require('../controller/user')
    const userValidator = require('../validator/user')
    const auth = require('../middleware/auth')
    const router = express.Router()
    
    // 用户登录
    router.post('/users/login', userValidator.login, userCtrl.login)
    // 用户注册
    router.post('/users', userValidator.register, userCtrl.register)
    // 获取当前登录用户
    router.get('/user', auth, userCtrl.getCurrentUser)
    // 更新当前登录用户
    router.put('/user', auth, userCtrl.updateCurrentUser)
    
    module.exports = router
    

提取控制器模块

  1. 用户相关路由:(router/user.js)

    const express = require('express')
    const userCtrl = require('../controller/user')
    const userValidator = require('../validator/user')
    const auth = require('../middleware/auth')
    const router = express.Router()
    
    // 用户登录
    router.post('/users/login', userValidator.login, userCtrl.login)
    // 用户注册
    router.post('/users', userValidator.register, userCtrl.register)
    // 获取当前登录用户
    router.get('/user', auth, userCtrl.getCurrentUser)
    // 更新当前登录用户
    router.put('/user', auth, userCtrl.updateCurrentUser)
    
    module.exports = router
    
  2. 用户的控制器模块:(/controller/user.js)

    const { User } = require('../model')
    const jwt = require('../util/jwt')
    const { jwtSecret } = require('../config/config.default')
    
    // 用户登录
    exports.login = async (req, res, next) => {
      try {
        // 1. 数据验证
        // 2. 生成 token
        const user = req.user.toJSON()
        const token = await jwt.sign({
          userId: user._id
        }, jwtSecret, {
          expiresIn: 60 * 60 * 24
        })
        // 3. 发送成功响应(包含 token 的用户信息)
        delete user.password
        res.status(200).json({
          ...user,
          token
        })
      } catch (err) {
        next(err)
      }
    }
    
    // 用户注册
    exports.register = async (req, res, next) => {
      try {
        let user = new User(req.body.user)
        await user.save()
        user = user.toJSON()
        delete user.password
        res.status(201).json({
          user
        })
      } catch (err) {
        next(err)
      }
    }
    
    // 获取当前登录用户
    exports.getCurrentUser = async (req, res, next) => {
      try {
        res.status(200).json({
          user: req.user
        })
      } catch (err) {
        next(err)
      }
    }
    
    // 更新当前登录用户
    exports.updateCurrentUser = async (req, res, next) => {
      try {
        // 处理请求
        res.send('updateCurrentUser')
      } catch (err) {
        next(err)
      }
    }
    
    // 获取指定用户资料
    exports.getUserProfile = async (req, res, next) => {
      try {
        // 处理请求
        res.send('getUserProfile')
      } catch (err) {
        next(err)
      }
    }
    
    // 关注用户
    exports.followUser = async (req, res, next) => {
      try {
        // 处理请求
        res.send('followUser')
      } catch (err) {
        next(err)
      }
    }
    
    // 取消关注用户
    exports.unfollowUser = async (req, res, next) => {
      try {
        // 处理请求
        res.send('unfollowUser')
      } catch (err) {
        next(err)
      }
    }
    

错误处理中间件

  1. 示例代码:(middleware/error-handler.js)

    // 通过 util 把错误数据发送到客户端
    const util = require('util')
    
    module.exports = () => {
      return (err, req, res, next) => {
        res.status(500).json({
          error: util.format(err) 
        })
      }
    }
    

将数据保存到数据库中

  1. 用户注册接口(router/user.js)

    const express = require('express')
    const userCtrl = require('../controller/user')
    const userValidator = require('../validator/user')
    const auth = require('../middleware/auth')
    const router = express.Router()
    
    // 用户注册
    router.post('/users', userValidator.register, userCtrl.register)
    
  2. 验证中间件(validator/user.js)

    const { body } = require('express-validator')
    const validate = require('../middleware/validate')
    const { User } = require('../model')
    const md5 = require('../util/md5')
    
    exports.register = validate([
      body('user.username')
        .notEmpty().withMessage('用户名不能为空')
        .custom(async username => {
          const user = await User.findOne({ username })
          if (user) {
            return Promise.reject('用户名已存在')
          }
        }),
      body('user.password').notEmpty().withMessage('密码不能为空'),
      body('user.email')
        .notEmpty().withMessage('邮箱不能为空')
        .isEmail().withMessage('邮箱格式不正确')
        .bail()
        .custom(async email => {
          const user = await User.findOne({ email })
          if (user) {
            return Promise.reject('邮箱已存在')
          }
        })
    ])
    
  3. 注册的控制器

    const { User } = require('../model')
    const jwt = require('../util/jwt')
    const { jwtSecret } = require('../config/config.default')
    
    // 用户注册
    exports.register = async (req, res, next) => {
      try {
        let user = new User(req.body.user)
        await user.save()
        user = user.toJSON()
        delete user.password
        res.status(201).json({
          user
        })
      } catch (err) {
        next(err)
      }
    }
    
  4. postman接口访问:

  5. mongo数据库结果展示:

使用 JWT

  1. 根据 jwt 中间件生成对应的 Promise 方法:(/util/jwt.js)

    const jwt = require('jsonwebtoken')
    const { promisify } = require('util')
    
    // 生成 pwt 的promise方法
    exports.sign = promisify(jwt.sign)
    
    // 验证 pwt 的promise方法
    exports.verify = promisify(jwt.verify)
    
    exports.decode = promisify(jwt.decode)
    
  2. 封装 jwt 验证中间件:(/middleware/auth.js)

    const { verify } = require('../util/jwt')
    const { jwtSecret } = require('../config/config.default')
    const { User } = require('../model')
    
    module.exports = async (req, res, next) => {
      // 从请求头获取 token 数据
      let token = req.headers['authorization']
      token = token ? token.split('Bearer ')[1] : null
    
      // 验证 token 是否有效
      // 无效 -> 响应 401 状态码
      // 有效 -> 把用户信息读取出来挂载到 req 请求对象上
      if (!token) {
        return res.status(401).end()
      }
    
      // 继续往后执行
      try {
        // verify 会处理 token 中过期时间等
        const decodedToken = await verify(token, jwtSecret)
        req.user = await User.findById(decodedToken.userId)
        next()
      } catch (err) {
        return res.status(401).end()
      }
    }
    
  3. 生成 token:(/controller/user.js)

    const { User } = require('../model')
    const jwt = require('../util/jwt')
    const { jwtSecret } = require('../config/config.default')
    
    // 用户登录
    exports.login = async (req, res, next) => {
      try {
        // 1. 数据验证
    
        // 2. 生成 token
        const user = req.user.toJSON()
        const token = await jwt.sign({ userId: user._id }, 
            jwtSecret, 
            { expiresIn: 60 * 60 * 24 }) // 设置过期时间(秒)
    
        // 3. 发送成功响应(包含 token 的用户信息)
        delete user.password
        res.status(200).json({
          ...user,
          token
        })
      } catch (err) {
        next(err)
      }
    }
    
  4. 将封装的中间件放到需要校验的 api 中:(/router/user.js)

    const express = require('express')
    const userCtrl = require('../controller/user')
    const userValidator = require('../validator/user')
    const auth = require('../middleware/auth')
    const router = express.Router()
    
    // 用户登录
    router.post('/users/login', userValidator.login, userCtrl.login)
    
    // 用户注册
    router.post('/users', userValidator.register, userCtrl.register)
    
    // 获取当前登录用户
    router.get('/user', auth, userCtrl.getCurrentUser)
    
    // 更新当前登录用户
    router.put('/user', auth, userCtrl.updateCurrentUser)
    
    module.exports = router
    

代码附件下载

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 项目目录
  2. 2. 配置常用中间件
  3. 3. 路由设计
  4. 4. 提取控制器模块
  5. 5. 错误处理中间件
  6. 6. 将数据保存到数据库中
  7. 7. 使用 JWT
  8. 8. 代码附件下载