egg-models-test v2.5.1
bt-egg
btclass 后端服务基础框架。
框架概述
框架本身一般只作集成功能,具体功能由插件实现。插件作为路径引用的方式仅适用于应用,不适合框架,每个插件都必须独成包。具体可见:https://eggjs.org/zh-cn/tutorials/progressive.html 插件需要维护自身的插件依赖。使用第三方插件需要初始化或有其它配置时,尽量包装成一个独立的插件,避免由框架实现具体功能。以后如果项目种类多了,还可以在 egg 框架的基础衍生出更多的框架。比如前端专用,微服务专用,这些框架可以自由组装未来越来越多的插件。
bt-egg 目前包含以下内容:
特性
插件
- btEggLogger, splunk 日志采集
- btEggOnError, 统一后端响应状态
- btEggUtils, 实用工具集
- btModels, MySQL ORM
- btEggOpenapi 可交互API文档 + 请求响应参数校验(未来:API健康状态上报, 填充默认请求参数, 转换字符串类型的数字)
- btEggServerRequest 服务间请求工具
基本使用
在项目根目录执行
npm install bt-egg --save
package.json
文件加入
{
"egg": { "framework": "bt-egg" }
}
特性
配置即代码
我们采用 egg 推荐的配置即代码的方式,需要解决的痛点就是敏感配置如何与开发者隔离,于是我们诞生了bt-data-locker
库用来解决这个问题,核心原理就是使用 RSA 非对称算法,将配置用公钥加密,然后运行时用私钥解密出原配置。PS:解密部分已经在框架中实现,开发者无需操作。
开发者使用步骤:
- 使用
不同环境
的公钥
去加密业务项目中的敏感配置,然后加入GIT
代码版本控制。 - 接下来在
config.default.js
添加一个 config.secretKeys = [],写明哪些配置 value 需要被解密。 - 最后把解密私钥放入
config/pem/private_key.pem
即可正常运行代码。
secretKeys 写法示例如下(示例也是框架中已经拥有的一些公共配置):
[
'models.sequelize.dbs.btclass.password',
'redis.default.password',
'btEggLogger.splunk.token',
'serverRequest.mysql.password',
]
test 环境公、私钥
public_key.pem
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ763+fQlpGa98VvASSY4naRz5jom2Nw
fHC8nP/t694CcWHtFWWISt9MNKVPNMCIFZ2HyJhmgicsLkF7gEVhkFMCAwEAAQ==
-----END PUBLIC KEY-----
private_key.pem
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAJ763+fQlpGa98VvASSY4naRz5jom2NwfHC8nP/t694CcWHtFWWI
St9MNKVPNMCIFZ2HyJhmgicsLkF7gEVhkFMCAwEAAQJAFxp2N4YEm5xdrX94Nw1Q
u9JszNfg3Q6XxvpiBn9Y66ZLm5MgNM90FMgrEN33Y/AfXCJohkx2SPfECHylC8eR
AQIhAPJj05tO/0aIAVJ+iM+zUdVoPlH/6wm2Amj4q7r9rgtzAiEAp+gXp61kVFPz
59J0B3W7e/suB0uwI3bp/FOnFnHU76ECIH63C0e0+6UOsspClhkm4JAVKAdMJ75y
5T2lSnm95r/bAiEApiWBksh+6PsR9SlI60DSvsI0L7/zkYRP0QGt6wXE4UECIQC/
REUkN9H1hqwQH+TwK1qnAyQUFfX4Zy171q3k9SU4Eg==
-----END RSA PRIVATE KEY-----
prod 环境公钥
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2qYe+P+qYHaGWnRvF488njYxB
FyEayCcvfdXtDJKA0wKf/YjxmGec3Et5zZzdI7H1+1lTXfFtCm+FFnkiCqmIXMNv
rsi+XK7iPo67IxJlwYTGqBaxwh/mlUmNg+yO+/pa9oxhfylw0c0k9Z7/Ql/cpsZ0
Tdu2M54UhIRlzSZG8QIDAQAB
-----END PUBLIC KEY-----
bt-data-locker
使用详解传送门。
插件
一般情况下,不要禁用本框架的插件。本框架作为公司 egg 项目的共同基础,不仅是公用设施,节省不必要的重复劳动,还是规范,约束大家的代码行为。
遇到特殊情况,可以用下面的方法禁用,以 bt-egg-logger 为例,在 config/plugin.js
里配置
// config/plugin.js
config.btEggLogger = false;
或者只在开发环境下禁用
// config/plugin.local.js
config.btEggLogger = false;
更加详细的介绍见 egg 文档插件篇。
bt-egg-logger
用于收集 splunk 收集日志,默认配置:
config.btEggLogger = {
task: 'bt-egg', // 项目名称
level: 'INFO', // 'DEBUG', 'INFO', 'WARN', 'ERROR'
stdout: true, // 是否输出到终端
splunk: {
token: '4C066829-8291-4C79-AEB1-0AA45A4FC190',
url: 'http://splunk.bt-tp.group',
port: 7788,
},
};
bt-egg-on-error
用于集中处理程序的出错行为。
错误抛出
禁止直接抛出字符串或者普通对象。对于字符串,可以在项目的 eslint 加入 https://eslint.org/docs/rules/no-throw-literal。支持将 egg-valitade error 的 Errors 属性附加到 message 属性上。
一般错误如下处理:
throw new Error('this is an error');
对于带有状态码的错误:
throw new this.app.HttpError({status: 401, message: 'this is a http error'});
throw new this.ctx.HttpError({status: 401, message: 'this is a http error'});
或者
throw new this.app.HttpError(401, 'this is a http error');
throw new this.ctx.HttpError(401, 'this is a http error');
错误记录
以往的代码,往往需要在 controller 做 try ... catch ...
const transaction = await sequelize.transaction();
try {
// ...
throw new Error('this is an error');
// ...
} catch(error) {
await transaction.rollback();
this.ctx.logger.error(error);
}
使用 btEggOnError 可以自动化处理错误记录。事务自动回滚由 bt-models
实现。
错误反馈
egg 自带的 egg-onerror 对开发期间的错误反馈非常友好,因此在开发环境不对其作修改,需要修改的可以参照 bt-egg-on-error 的配置。
在生产环境下,对于以 .html
结尾的路由,返回错误页面(TODO 这部分还需改进),其他路由返回以下如下响应。
{
code: error.status || 500,
msg: (error.status && error.status !== 500 ? error.message : '服务出错了'),
}
btEggOpenapi
由于 swagger 2.0
规范升级到了v3
版本,社区将规范名称改回openapi
,再加上本插件可直接校验请求参数,所以直接替换掉之前的bt-egg-swagger
插件。未来可能会在此插件上新增一些特性。
使用方法:只要将openapi 描述文档放置在/app/public/openapi/index.yaml
即可。
Swagger GUI:http://localhost:7001/openapi.doc
转换的 JSON 描述:http://localhost:7001/openapi.json
注:使用 swagger 2.0的,要将语法转换为 3.0版本,转换地址。目前不支持
$ref
外部文件引用;
bt-egg-utils
工具函数库
目前有以下两个挂载在 ctx 上的方法。
module.exports = {
success(data) {
this.status = 200;
this.body = {
code: 200,
};
if (data) {
this.body.res = data;
}
},
/**
* 获取请求 query 数组类型参数,支持通用写法 ?a=1&a=2 和逗号分隔法,自动转换整型
* 使用逗号分隔法时,url 的参数为复数,即 ${paramName}s(TODO 后续会改进为真正的英语复数)
* @param {string} paramName - 参数名.
* @return {Array} 合成的数组
*/
getPluralQuery(paramName) {
// ...
},
};
bt-models
这是一个中间件。
配置选项为
// config.default.js
exports.models = {
};
无须使用的项目可以这样禁用
// config.default.js
exports.models= {
enable: false;
};
需要单独安装 bt-sequelize-tables 包; 默认的 table 来源是 bt-sequelize-tables; 默认的 extension 来源是 app/models; 使用 app.logger.info 作为全局 log 函数; 使用 ctx.logger.info 作为 ctx 打印函数; 更详细的配置和使用说明见 bt-models 项目。
bt-egg-server-request
服务间请求调用工具,挂载在 Application
对象下,Application
对象几乎可以在编写应用时的任何一个地方获取到。Lib传送门
配置:
// config.default.js
config.serverRequest = {
mysql: {
host: mysqlConf.host,
database: mysqlConf.database,
user: mysqlConf.user,
password: mysqlConf.password,
},
};
使用:this.app.serverRequest.selfAjax(...);