一. 新建项目

新建一个文件夹,然后初始化成一个node项目,注意node版本要在 v7.6.0以上

$ cd project
$ npm init

然后安装koa

$ npm install koa

然后在当前目录下新建一个app.js,里面加入一点简单的代码就能跑起来了

const Koa = require('koa');
const app = new Koa();

// response
app.use(ctx => {
  ctx.body = 'Hello Koa';
});

app.listen(3000);
$ node app.js

二.加入各种插件

1.路由

$ npm install koa-router
...
const Router = require('koa-router');
let router = new Router();
...
router.get("/hello", async (ctx, next) => {
  ctx.body = 'Hello Koa';
})

router.post("/hello2", async (ctx, next) => {
  ctx.redirect("/hello")
})

...
app
  .use(router.routes())
  .use(router.allowedMethods());

2.session

$ npm install koa-session
...
const session = require('koa-session');
const sessionConfig = {
  key: 'koa:sess', 
  maxAge: 86400000,
  autoCommit: true, 
  overwrite: true, 
  httpOnly: true, 
  signed: true, 
  rolling: false, 
  renew: false 
}
app.keys = ['12345678'];
app.use(session(sessionConfig, app));

之后就可以在请求中操作session了

router.get("/hello", async (ctx, next) => {
  ctx.session.foo = 'bar';
  let { baz } = ctx.session.foo
 ...
})

3. 视图组件

这里选的是ejs,实际上选择还是挺多的

$ npm install koa-views ejs
const views = require('koa-views');

app.use(views(__dirname + '/views', {
  extension: 'ejs'
}));

之后就可以渲染模板了

router.get("/hello", async (ctx, next) => {
  await ctx.render('pages/hello');
})

新建pages目录,然后新建hello.ejs就可以了,ejs语法

4.请求体解析

koa默认情况下无法获得request.body,这也算是挺奇葩的…

$ npm install koa-bodyparser
app.use(bodyParser());

然后就可以拿到前端表单提交的内容了

router.post("/hello", async (ctx, next) => {
  let { body } = ctx.request
})

5. 日志

$ npm install koa-log4

实际上用的是log4js
由于logger代码内容比较多,把它放到另外的文件中去, /config/logger.js

const log4js = require('koa-log4');
const node_env = process.env.NODE_ENV || 'development'
module.exports = options => {
    return async (ctx, next) => {
        const request_id = Math.random().toString(36).substr(2);
        const start = Date.now();
        log4js.configure({
            appenders: {
                development: {
                  type: 'console'
                },

                production: {
                    type: 'dateFile',
                    encoding: 'utf-8',
                    filename: `logs/${node_env}`,
                    layout: {
                        type: "pattern",
                        pattern: `[%d] [%p] [${request_id}] %m`
                    },
                    pattern: "-yyyy-MM-dd.log",
                    alwaysIncludePattern: true,
                },
            },
            categories: {default: {appenders: [node_env], level: 'info'}}
        });
        const logger = log4js.getLogger(node_env);
        ctx.logger = logger;
        logger.info(`START ${ctx.method} ${decodeURI(ctx.url)} WITH PARAMETERS ${JSON.stringify(ctx.request.body)} FROM ${ctx.ip}`)
        await next();
        const end = Date.now();
        const responseTime = end - start;
        logger.info(`DONE WITH STATUS: ${ctx.response.status} IN ${(responseTime / 1000).toFixed(4)}s`);
    }
};

然后再到app.js中去使用

const logger = require('./config/logger');
app.use(logger())

日志分成了开发和生产,开发模式下只要直接打在console里就行,生产模式下需要将日志保存成文件

到此为止一个基本的网络框架需要用的东西都齐全了

完整的app.js

const Koa = require('koa');
const Router = require('koa-router');
const views = require('koa-views');
const bodyParser = require('koa-bodyparser');
const session = require('koa-session');
const sessionConfig = require("./config/session");
const logger = require('./config/logger');
const app = new Koa();
let router = new Router();

app.keys = ['12345678'];
app.use(session(sessionConfig, app));
app.use(bodyParser());
app.use(views(__dirname + '/views', {
  extension: 'ejs'
}));
app.use(logger())

//XXXroutes

app
  .use(router.routes())
  .use(router.allowedMethods());

app.listen(4200);

三. 部署

1. 使用pm2

$ npm install -g pm2

新建pm2.config.json

{
  "name"   : "app",
  "script" : "app.js",
  "env": {
    "NODE_ENV": "production"
  }
}
$ pm2 start pm2.config.json

2.使用docker

新建Dockerfile

FROM node:12.4.0-alpine

ENV NODE_ENV=production
ENV APP_ROOT /var/www/syoo_collect
WORKDIR $APP_ROOT

VOLUME [ "/var/www/app/logs" ]

EXPOSE 4200

ADD package*json $APP_ROOT/

RUN npm install

ADD app.js $APP_ROOT/
ADD config/ $APP_ROOT/config
ADD views/ $APP_ROOT/views

CMD ["node", "app.js"]

启动脚本

$ docker build -t app . && docker ps -q --filter ancestor='app' | xargs docker stop && docker run -d -v $(pwd)/logs:/var/www/app/logs -p 4200:4200 app