10月13, 2017

node写后台的一些记录

记录一下我在用node写后台的一些点。

文档

一开始其实是需要后端给出接口定义的。

所以我就找了一些swagger-node的一些方案,但最终不了了之,主要是我不想花太多的时间精力在这个上面。(当然后面还是会把这块给弥补掉)。

最后我选择了apiDoc

用着还行,主要有两点不舒服:

  • 所有的接口初始version是0.0.0,目前没有找到统一处理的地方
  • 接口不支持order字段,需要手工在json文件中,自己去做指定

当然其他的点还是可以的,特别是接口有一个历史版本,可以做对比记录。

处理成功/失败返回

这个看似简单,但处理起来还是有些麻烦。拿我司来说,所有的返回结果必须如下:

{
     "head": {
          "code": "",
          "status": "",
          "msg": ""
     },
     body: []
}

我们不可能每一个请求都去人为地处理,所以需要自己实现一个ApiResponse的类:

class ApiResponse {
    static success(body) {
        return new ApiResponse().head({
            code: "000000",
            message: "成功",
            status: ApiResponse.SUCCESS_STATUS
        }).body(body);
    }

    static error(head, body) {
        head.code = head.code || "000001";
        head.status = ApiResponse.ERROR_STATUS;
        return new ApiResponse().head(head);
    }

    head(head) {
        this.setHead(head);
        return this;
    }

    body(body) {
        this.setBody(body);
        return this;
    }

    setHead(head) {
        this.head = head;
    }

    setBody(body) {
        this.body = body;
    }
}

ApiResponse.SUCCESS_STATUS = "Y";
ApiResponse.ERROR_STATUS = "N";

module.exports = ApiResponse;

然后实际代码中,只要调用ApiResponse.success()ApiResponse.error()即可。

日志记录

我使用了koa-looger

const log4js = require('koa-log4');

log4js.configure({
    appenders: [{
        type: 'DateFile',
        filename: './log/default.log',
        pattern: '-yyyy-MM-dd.log',
        alwaysIncludePattern: true
    }]
})

const log = log4js.getLogger();

module.exports = log;

alt

目前log4js记录的是执行时间、异常信息及SQL的执行语句,还有可能要输出的一些信息,比如上传文件成功之类的。

异常信息处理

这个做的是集中管理,统一在所有的路由器那里封装:

const log = require("../common/logger.js");
const ApiResponse = require("../common/apiResponse");

const Router = require('koa-router');
const router = new Router({
    prefix: '/api'
});

router.all('/*', async function(ctx, next){
    // ctx.set("X-XSS-Protection", 0);
    var start = Date.now();
    try{
        await next();
    } catch(e) {
        log.error(e);
        ctx.body = ApiResponse.error({msg: "系统发生错误"});
    }
    var ms = Date.now() - start;
    log.info(`请求URL:${ctx.path},请求耗时:${ms + 'ms'}`);
    ctx.set('X-Response-Time', ms + 'ms');
});

module.exports = router;

需要注意的点是,不能让前端看到具体的错误信息,以免让对方能猜到一些信息,从而来做一些危害网站的事,譬如SQL注入之类的。

sequelize的orm库使用

因为我选择的是传统型数据库:mysql,所以为了防SQL注入,以及操作方便,最终选择了sequelize

基本上看看这篇文章,就差不多能使用了。

用到的无非是这样:

  • findAll() 查找全部,可能会加where条件,还有只返回include的字段,起别名之类的
  • findOne()
  • findById()
  • create
  • update
  • destory
  • ...

在设计表的时候,可以给表加两个字段:created_at和updated_at

const Sequelize = require('sequelize');
const log = require("../common/logger");
const config = require("../config");
const { db } = config;

const sequelize = new Sequelize({
    host: db.host,
    database: db.database,
    username: db.username,
    password: db.password,
    define: {
        freezeTableName: true
    },
    logging: function(sql) {
        log.info(sql);
    }
})
module.exports = sequelize;
const sequelize = require("./sequelize");
const Sequelize = require("sequelize");

const Category = sequelize.define('Category', {
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    zh_name: Sequelize.STRING(45),
    en_name: Sequelize.STRING(45)
}, {
    tableName: 'category',
    underscored: true
});

module.exports = Category;

这里的underscored要设置为true,它才会把createdAtupdatedAt给转成created_atupdated_at。当然这个功能也可以关掉,看个人选择,我觉得挺好的。包括sequelize还提供出一个:deletedAt,有了它,就不需要被物理删除了,而是作为标记删除。

文件上传处理

本想将文件放到服务端的,但后来想想不是太妥。服务端最好只做服务端(业务逻辑)的事,而文件存储这个功能应该抛给三方去实现。

一般业内可选择的方案:七牛、亚马逊等。

七牛貌似不能本地搭建,所以就选择了亚马逊的Minio

这货文档有两个坑,javascripts的api,它有一个参数默认你的协议是https。然后docker环境配置少了-d参数,导致在前台运行环境。

说到docker,我觉得比较坑的一点是网络问题,在一开始搞docker的时候,还报了一个和iptables相关的错误,折腾了好久。。

这里主要需要深入的是三点:

  • 上传文件
  • 删除文件
  • 给包设置访问权限

它的查询(例如limit),被我放弃了。因为我将文件单独做了一张表,这样一来操作也容易。

配置中心

比如mysql的配置,minio的配置,目前我还没做这一块。

不过业内应该也有相关的方案,我司有一个配置中心,但目前接不了node端。

本文链接:www.my-fe.pub/post/node-write-website-note.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。