一、前言
前面我们介绍了 await / async 的基本使用,学到了 koa2 框架的安装、项目的创建,以及路由的基本使用。
接下来,我们正式使用 koa2 对我们的 myblog 博客项目进行重构!
二、实现 session
终端安装一些必要的东西(koa-generic-session、koa-redis、redis),更容易实现登录
npm i koa-generic-session koa-redis redis
修改 app.js 文件
app.js
const session = require('koa-generic-session') const redisStore = require('koa-redis') ...... // session 配置(在routes前面) app.keys = ['Qianduan2023'] app.use(session({ // 配置 cookier cookie: { path: '/', httpOnly: true, maxAge: 24 * 60 * 60 * 1000 }, // 配置 redis store: redisStore({ all: '127.0.0.1:6379' // 本地 reids }) }))
我们在 user.js 中创建一个 session-test 做测试
user.js
router.get('/session-test', async function(ctx, next) { if (ctx.session.viewCount == null) { ctx.session.viewCount = 0 } ctx.session.viewCount++ ctx.body = { errno: 0, viewCount: ctx.session.viewCount } })
三、开发路由
1、安装 mysql 和 xss
终端键入以下代码,安装 mysql 和 xss
npm i mysql xss
2、代码迁移
修改 app.js 文件,修改本地 redis 的写法
app.js
const { REDIS_CONF } = require('./conf/db') ...... // 配置 redis store: redisStore({ // all: '127.0.0.1:6379' // 本地 reids all: `${REDIS_CONF.host}:${REDIS_CONF.port}` })
3、修改 controller 控制器
修改 controller 文件里的内容(主要是修改成 async/await 的形式)
./controller.blog.js
// 导入执行 sql 的相关内容 const xss = require('xss') const { exec } = require('../db/mysql') // 获取博客列表(通过作者和关键字) const getList = async (author, keyword) => { // 1=1 是为了语法的绝对正确,注意以下 sql 拼接时的空格 let sql = `select * from blogs where 1=1 ` if (author) { sql += `and author='${author}' ` } if (keyword) { sql += `and title like '%${keyword}%' ` } // 以时间的倒序 sql += `order by createtime desc;` // 返回 promise return await exec(sql) } // 获取博客详情(通过 id) const getDetail = async (id) => { const sql = `select * from blogs where id='${id}'` const rows = await exec(sql) return rows[0] } // 新建博客 newBlog 若没有,就给它一个空对象 const newBlog = async (blogData = {}) => { // blogData 是一个博客对象,包含 title content author 属性 const title = xss(blogData.title) const content = xss(blogData.content) const author = blogData.author const createTime = Date.now() const sql = ` insert into blogs (title, content, createtime, author) values ('${title}', '${content}', '${createTime}', '${author}'); ` const insertData = await exec(sql) return { id: insertData.insertId } } // 更新博客(通过 id 更新) const updateBlog = async (id, blogData = {}) => { // id 就是要更新博客的 id // blogData 是一个博客对象 包含 title content 属性 const title = xss(blogData.title) const content = xss(blogData.content) const sql = ` update blogs set title='${title}', content='${content}' where id=${id} ` const updateData = await exec(sql) // 更新的影响行数大于 0,则返回 true if (updateData.affectedRows > 0) { return true } return false } // 删除博客(通过 id 删除) const delBlog = async (id, author) => { const sql = `delete from blogs where id='${id}' and author='${author}'` const delData = await exec(sql) if (delData.affectedRows > 0) { return true } return false } // 导出共享 module.exports = { getList, getDetail, newBlog, updateBlog, delBlog }
./controller/user.js
const { exec, escape } = require('../db/mysql') const { genPassword } = require('../utils/cryp') // 登录(通过用户名和密码) const login = async (username, password) => { username = escape(username) // 生成加密密码 password = genPassword(password) password = escape(password) const sql = ` select username, realname from users where username=${username} and password=${password} ` const rows = await exec(sql) return rows[0] } // 导出共享 module.exports = { login }
4、开发路由
开发 ./routes 文件里的路由,直接拷贝 blog-express 文件里的内容,使用 koa2 规定的格式即可
./routes/blog.js
const router = require('koa-router')() // 导入博客和用户控制器相关内容 const { getList, getDetail, newBlog, updateBlog, delBlog } = require('../controller/blog') // 导入成功和失败的模型 const { SuccessModel, ErrorModel } = require('../model/resModel') const loginCheck = require('../middleware/loginCheck') // 前缀 router.prefix('/api/blog') router.get('/list', async function (ctx, next) { // 博客的作者,req.query 用在 GET 请求中 let author = ctx.query.author || '' // 博客的关键字 const keyword = ctx.query.keyword || '' if (ctx.query.isadmin) { // 管理员界面 if (ctx.session.username == null) { // 未登录 ctx.body = new ErrorModel('未登录') return } // 强制查询自己的博客 author = ctx.session.username } // 查询的结果 const listData = await getList(author, keyword) ctx.body = new SuccessModel(listData) }) router.get('/detail', async function (ctx, next) { const data = await getDetail(ctx.query.id) ctx.body = new SuccessModel(data) }) router.post('/new', loginCheck, async function (ctx, next) { const body = ctx.request.body body.author = ctx.session.username const data = await newBlog(body) ctx.body = new SuccessModel(data) }) router.post('/update', loginCheck, async function (ctx, next) { const val = await updateBlog(ctx.query.id, ctx.body) if (val) { ctx.body = new SuccessModel() } else { ctx.body = new ErrorModel('更新博客失败') } }) router.post('/del', loginCheck, async function (ctx, next) { const author = ctx.session.username const val = await delBlog(ctx.query.id, author) if (val) { ctx.body = new SuccessModel() } else { ctx.body = new ErrorModel('删除博客失败') } }) module.exports = router
./routes/user.js
const router = require('koa-router')() const { login } = require('../controller/user') const { SuccessModel, ErrorModel } = require('../model/resModel') // 前缀 router.prefix('/api/user') // 路由的中间件必须是个 async 函数 router.post('/login', async function (ctx, next) { // 通过 request.body 获取 const { username, password } = ctx.request.body const data = await login(username, password) if (data.username) { // 设置 session ctx.session.username = data.username ctx.session.realname = data.realname ctx.body = new SuccessModel() return } ctx.body = new ErrorModel('登录失败') }) module.exports = router
四、联调
启动 redis,开启 nginx
后端:npm run dev
前端:http-server -p 8001
五、日志
终端键入安装 koa-morgan
npm i koa-morgan
修改 app.js 文件
app.js
const path = require('path') const fs = require('fs') const morgan = require('koa-morgan') ...... // 日志记录 const ENV = process.env.NODE_ENV if (ENV !== 'production') { // 开发环境 / 测试环境 app.use(morgan('dev')) } else { // 线上环境使用 combined(写入文件) const logFileName = path.join(__dirname, 'logs', 'access.log') const writeStream = fs.createWriteStream(logFileName, { flags: 'a' }) app.use(morgan('combined', { stream: writeStream })); }
同样的,修改 package.json 文件
package.json
"prd": "cross-env NODE_ENV=production nodemon ./bin/www"
npm run prd,运行文件,之后打开几个页面,查看 access.log 文件的内容
六、写在最后
至此,我们明白了 如何使用 Koa2 框架对我们的 myblog 项目进行进一步的重构(实现session、开发路由、联调、日志), 本系列文章暂告一段落!
如果你需要该项目的 源码,请通过本篇文章最下面的方式 加入 进来~~