新建一个开发文件夹 比如 node-demo
并初始化
npm init -y
pm2是一个进程管理工具,需要全局安装
npm i pm2 -g
nodemon是一个node文件启动工具,可以自动检测到目录中的文件更改,通过重启应用程序来调试基于node.js的应用程序
npm install nodemon --save-dev
安装koa框架
npm i koa --save
在package.json
的"script"
命令下加入以下命令:
"dev":"nodemon app.js",
"start":"pm2 start app.js --name your-project-name --watch"
注:
npm run dev
用作开发调试,npm run start
用作测试或生产启动
项目根目录下新建app.js
,用于实例化Koa
,启动一个node
服务器,内容如下
const Koa = require("koa");
const app = new Koa();
const PORT = 3000;
app.listen(PORT,()=>{
console.log(`App is running at http://127.0.0.1:${PORT}`)
})
router其实也是一种中间件
考虑到一个中间层可能对接不同的前端项目,因此路由设置应划分模块
例如,中间层有两个模块module_1和module_2,这个时候再写在app.js中难免混乱,最好以中间件的形式剥离出来
在根目录下创建router.js,内容如下
const KoaRouter = require("koa-router");
const router = new KoaRouter();
module.exports = app => {
router.use("/test",async ctx=>{
ctx.body = ‘test success‘;
})
app.use(router.routes()).use(router.allowedMethods());
}
在app.js中
const router = require("./router");
...
router(app);
app.listen...
为了区分开发,测试和生产环境,需要进行多环境配置
安装依赖
npm install config --save
在项目根目录下建立config文件夹
新建default.json,staging.json,production.json文件
例如在default.json中
{
"port":"3000"
}
在staging.json中
{
"port":"3001"
},
在production.json中
{
"port":"3002"
}
在app.js中引入
const Koa = require("koa");
const config = require("config");
const app = new Koa();
--- const PORT = 3000;
+++ const PORT = config.get("port")
app.listen(PORT,()=>{
console.log(`App is running at http://127.0.0.1:${PORT}`)
})
其他需要多环境配置的变量引入方法类似
同时设置package.json中的scripts:
"staging":"export NODE_ENV=staging&&npm start",
"production":"export NODE_ENV=production&&npm start"
koa最大的特点就是独特的中间件流程控制,是一个典型的洋葱圈模型.koa2在node7.6之后可以直接使用async/await使用中间件.下图很清晰的表明了一个请求是如何经过中间件最后生成响应的,这种模式开发和使用中间件都是非常方便的.
一个中间层对应的可能不止一个前端项目,为了多人开发,不同模块的controller,servicer,router和通信的配置肯定不能混成一锅粥,这里的解决方案是以路由作为模块划分的标识.
例如有两个模块module_a和module_b,我们在根目录下新建两个文件夹module_a和module_b.我们以module_a为例,在module_a下新建router.js,内容如下:
const router = require("koa-router")();
router.get("/test",async (ctx)=>{
ctx.body = "module_a test";
})
module.exports = router.routes();
同时,在根目录下的router.js文件夹下要注册module_a的路由
...
module.exports = app => {
router.use("/module_a",require("./module_a/router"))
...
router.get("/test",async ctx=>{
运行在服务器的程序需要日志来记录程序的运行状况,这里推荐使用log4js
安装依赖
npm i log4js --save
最好把log设置成中间件
在middleware文件夹下新建logger文件夹
分别新建index.js,logger.js,access.js文件,
index.js负责封装logger中间件,logger.js主要写入一些logger的配置,access.js主要配置日志的访问信息
在logger.js文件中(注意不同环境进行不同的日志级别配置
{
logInfo:{
env:"dev",
level:"debug",
dir:"logs"
}
}
)
const log4js = require(‘log4js‘);
const methods = ["trace","debug","info","warn","error","fatal","mark"];
const logInfo = require("config").get("logInfo");
const access = require("./access");
module.exports = () =>{
const {env,level,dir} = logInfo;
const contextLogger = {};
const appenders = {};
appenders.nodeLog = {
type:"dateFile",
filename:`${dir}/task`,
pattern:`-yyyy-MM-dd.log`,
alwaysIncludePattern:true
};
if(env === ‘dev‘){
appenders.out = {
type:"console"
}
}
let config = {
appenders,
categories:{
default:{
appenders:Object.keys(appenders),
level,
}
}
}
const logger = log4js.getLogger(‘nodeLog‘);
log4js.configure(config);
return async (ctx,next) => {
const commonInfo = {};
const start = Date.now();
methods.forEach(method=>{
contextLogger[method] = message => {
logger[method](access(ctx,message,commonInfo))
}
})
ctx.log = contextLogger;
await next();
const end = Date.now();
const responseTime = end - start;
logger.info(access(ctx,{
responseTime:`响应时间为${responseTime/1000}s`
},commonInfo))
}
}
在access.js文件中
module.exports = (ctx,message,commonInfo) => {
const { method,url,host,headers } = ctx.request;
const client = {
method,url,host,message,referer:headers[‘referer‘],userAgent:headers[‘user-agent‘]
}
return JSON.stringify(Object.assign(commonInfo,client))
}
在index.js文件中
const logger = require("./logger");
module.exports = () => {
return logger();
}
随后在middleware的index.js中引入
const logger = require("./logger");
...
app.use(logger())
...
异常处理以中间件的方式,根据洋葱圈模型,中间件应该置于最外层的await next()之后捕获,这样能确保捕获到所有异常
在middleware下新建handleError.js,并设置如下
module.exports = async (ctx,next)=>{
await next().catch(err=>{
// 在日志系统中写入这个错误
ctx.log.error(err.message)
//保证能正常返回给前端,注意:这里可能需要判断401或403,根据业务类型,下面的内容也不同
ctx.status = 200;
ctx.body = {
code:-1,
success:false,
data:null,
msg:"中间层异常",
}
})
}
在middleware的index.js下注册这个中间件(放到中间件顺序的第一位)
const handleError = require("./handleError");
....
app.use(handleError)
....
原文:https://www.cnblogs.com/cheeliu/p/14789078.html