有时候我们需要记录用户进行了哪些操作,比如删除、更新和添加。这部分是要呈献给用户的,所以一定不能直接把系统日志的一大坨给他们。
系统后台采用了Koa2,数据库是mongo,借助mongoose操作数据库。
Model设计
设计Log结构
const mongoose = require('../tool/db-util').mongoose
const Schema = mongoose.Schema
const logSchema = new Schema({
index: Number,
nickname: String,
userId: String,
date: {type: Date, default: Date.now},
// request
method: String,
host: String,
url: String,
// response
status: Number,
desc: String
})
const LogModel = mongoose.model('log', logSchema)
module.exports = {
LogModel
}
中间件
这里参考了土豆zmb写的中间件,我根据自己应用的实际情况作了点修改。因为用户请求时携带着token,所以我在中间件里面获取到了用户的基本信息。
const jwt = require('jsonwebtoken')
const config = require('../config')
const logController = require('../controllers/log')
module.exports = async (ctx, next) => {
if (ctx.method === 'GET') {
// 不记录get请求
await next()
} else {
let token = ctx.request.header.authorization
if (token) {
const secret = config.System.token_secret
let payload = null
try {
payload = await jwt.verify(token.split(' ')[1], secret, {expiresIn: '1h'})
} catch (e) {
payload = {}
}
global.log = {
nickname: payload.nickname,
userId: payload._id,
method: ctx.request.method,
host: ctx.request.header.host,
url: ctx.request.url,
status: null,
desc: null
}
await next()
// 保存
if (global.log.desc) {
global.log.status = ctx.response.status
logController.add(global.log)
}
}
}
}
控制层LogController
const logService = require('../services/log')
class LogController {
static async add (content) {
await logService.add(content)
}
static async all (ctx) {
let opt = ctx.request.query
let {page = 1, size = 10, ...condition} = opt
let content = await logService.all(condition, Number(page), Number(size))
ctx.success({content})
}
}
module.exports = LogController
服务层LogService
查询时将几个需要展示的字段查出来,这里用了分页查询和降序。
const LogModel = require('../models/log').LogModel
class LogService {
static async add (content) {
let log = new LogModel(content)
await log.save()
}
static async all (condition, page, size) {
let logs = await LogModel.find(condition, '_id nickname date host status desc').skip((page - 1) * size).sort({_id: -1}).limit(size)
let count = await LogModel.count(condition)
return {logs, page: {page, size, count}}
}
}
module.exports = LogService
应用
在需要记录的地方,设置global.log.desc的值就可以了。如果不设置的话,记录到数据库中的内容为空。用户操作记录,只需要在控制层记录就可以了。如果需要留下更详细的记录,那就再服务层设置了。
这里以用户的一个登录操作为例:
class UserController {
static async signIn (ctx) {
let opt = ctx.request.body
let user = await userService.signIn(opt)
const secret = config.System.token_secret
if (user) {
const token = jwt.sign(user.toJSON(), secret, {expiresIn: '1h'}) // token签名 有效期为1小时
ctx.success({content: {user, token}})
global.log.desc = `${user.nickname}登录`
} else {
ctx.error({status: 200, error: '登录失败'})
}
}