目录如下:
image.png
app.js
const path = require('path')
const config = require('./config')
const router = require('./router')
const Koa = require('koa')
const logger = require('koa-logger')
const bodyParser = require('koa-bodyparser')
const serve = require('koa-static')
const cors = require('koa-cors')
const convert = require('koa-convert')
const jwt = require('koa-jwt')
const errorHandler = require('./middlewares/errorhandler')
const log = require('./utils/log')
const Token = require('./utils/token')
const app = new Koa()
require('events').EventEmitter.defaultMaxListeners = 15
const mongoose = require('mongoose')
mongoose.connect(config.db.url)
const port = config.port || '8080'
const secret = Token.getSecret('public.pem')
const jwtOpts = {
secret,
isRevoked: Token.isRevoked, // 判断token是否过期
tokenKey: 'token' // 设置ctx.state.token
}
const jwtUnlessOpts = {
path: [
/^\/api\/register/,
/^\/api\/login/,
/^\/api\/getMenuList/,
/^\/api\/getPage/,
/^\/api\/getDetailPage/,
/^\/js/,
/^\/css/,
/^\/fonts/,
/.jpg$/
]
}
// middlewares
const middlewares = [
convert(cors()),
logger(),
bodyParser(),
serve(path.join(__dirname, config.publicPath)),
serve(path.join(__dirname, config.uploadPath)),
// 验证是否需要token请求,unless是例外,不需要token就可以请求
jwt(jwtOpts).unless(jwtUnlessOpts),
errorHandler,
router.routes(),
router.allowedMethods()
]
middlewares.forEach(middleware => {
if (!middleware) {
return
}
app.use(middleware)
})
app.on('error', (err) => {
log('cyan', err)
})
// koa static server
const server = app.listen(port, () => {
log('magenta', 'The server is start on port ' + port)
})
// terminal ctrl+c to exit the server
process.on('SIGINT', () => {
log('yellow', 'Stopping dev server')
server.close(() => {
process.exit(0)
})
})
config.js
// server config
const config = {
port: 3000, // server port
db: {
url: 'mongodb://localhost:27017/blog'
},
publicPath: '../static',
uploadPath: '../uploads',
secretKey: 'halapro'
}
module.exports = config
token.js
const fs = require('fs')
const path = require('path')
const jwt = require('jsonwebtoken')
module.exports = {
getSecret (file) {
return fs.readFileSync(path.join(__dirname, '../config/' + file))
},
// 通过私钥生成token
generateToken (data) {
// 过期时间
let date = Math.floor(Date.now() / 1000)
const cert = this.getSecret('private.pem')
const token = jwt.sign({data, exp: date + 3600 * 24}, cert, { algorithm: 'RS256' })
return token
},
verifyToken (token) {
if (token) {
let res
const cert = this.getSecret('public.pem')
try {
let result = jwt.verify(token, cert, { algorithm: 'RS256' }) || {}
let { exp = 0 } = result, current = Math.floor(Date.now() / 1000)
if (current <= exp) {
res = result.data || {}
}
} catch (err) {
console.log('verifyToken error:', err)
throw err
}
return res
}
},
isRevoked (ctx, decodedToken, token) {
let currentTime = Math.floor(Date.now() / 1000)
let { exp = 0 } = decodedToken, current = Math.floor(Date.now() / 1000)
if (current <= exp) {
return 0
} else {
return 1
}
}
}
errorHandler.js
/**
* @description 异常处理
* @author halapro.liu
* @param {*} ctx
* @param {*} next
*/
const errorHandler = async (ctx, next) => {
try {
await next()
} catch (err) {
console.log(`--------------------------------err---------------------------:`, err)
ctx.status = err.statusCode || err.status || '500'
ctx.body = {
code: ctx.status,
message: err.message
}
}
}
module.exports = errorHandler