项目目录
配置常用中间件
-
常用中间件:
- 解析请求体: express.json()、 express.urlencoded()
- 日志输出: morgan()
- 为客户端提供跨域资源请求 cors()
-
示例代码:
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}`) })
路由设计
-
剥离每个模块的路由:(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
-
用户相关路由:(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
-
…
提取控制器模块
-
用户相关路由:(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
-
用户的控制器模块:(/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) } }
错误处理中间件
-
示例代码:(middleware/error-handler.js)
// 通过 util 把错误数据发送到客户端 const util = require('util') module.exports = () => { return (err, req, res, next) => { res.status(500).json({ error: util.format(err) }) } }
将数据保存到数据库中
-
用户注册接口(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)
-
验证中间件(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('邮箱已存在') } }) ])
-
注册的控制器
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) } }
-
postman接口访问:
-
mongo数据库结果展示:
使用 JWT
-
根据 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)
-
封装 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() } }
-
生成 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) } }
-
将封装的中间件放到需要校验的 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
代码附件下载
Express👉 常用场景
上一篇