node-maya v1.0.1
node-maya
本地开发
- 让 maya-server 子项目以 link 的方式引用 node-maya
cd node-maya
pnpm link .
cd node-maya/maya-server
pnpm link node-maya
- 让 node-maya 代码自动检测变化并编译
pnpm run build:watch
- 运行子项目 maya-server
pnpm start
单元测试
- 命令
pnpm run test
执行单元测试并显示覆盖率 - 命令
pnpm run test:debug
进入调试模式,在 Chrome 浏览器中打开chrome://inspect/#devices
页面,点击 Remote Target 下面的 inspect 即可进入调试页面
安装
npm install node-maya
测试 v
npm run test
测试覆盖率
npm run test:cov
转发请求
配置 multer(用于解析上传文件)
在 main.ts 中引用 multer,模式使用内存
import multer from 'multer' // 采用内存,直接二进制转发 const upload = multer({ storage: multer.memoryStorage() })
在 main.ts 的 bootstrap 方法中使用该中间件
app.use(upload.any()) // 由于上传的控件 name 名字不确定,故使用 multer 的 any 方法
全局添加错误过滤器组件
作用:- 会捕获接口中的异常错误,添加错误日志,并统一错误返回值结果
- 由于转发路由在项目中不存在,故会被异常捕获到 404 错误,这时过滤器便会转发该请求
用法如下: 在 main.ts 中引用 AllExceptionsFilter,bootstrap 方法中全局引用js import { AllExceptionsFilter } from 'node-maya'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new AllExceptionsFilter()); await app.listen(3000); }
转发接口
Maya 中默认的转发接口是通过环境变量 Backend + 请求的原始路由拼接而成。而在实际项目中,可能会存在自定义路由转发,或者转发后需要修改返回的结果集。这时候就要通过 Maya 提供的 forward 方法了。
首先 forward 的方法参数为:
- req
- res
- path // 接口路由 (如不填,则转发接口路由为 Backend + req.baseUrl)
Options
interface Options extends request.CoreOptions { query?: object; /** * 在响应浏览器之前,处理一下返回值。 */ handle?: (data: any) => any; headers?: | object | string[] | ((object: object, request: Request) => object); }
Example:
import { forward } from 'node-maya';
@Get('/forward-big-data')
getBigData(@Req() req, @Res() res) {
return forward(req, res, '/example/big-data');
}
RequestId 中间件使用
此中间件用于对每次请求的头部添加 X-Request-Id,用于以后的日志查询链路追踪。并且在上下文中可直接获取该 requestId
- 用法如下: 在 app.module.ts 中 AppModule 添加配置信息
import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common'
import { RequestIdMiddleware } from 'node-maya'
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(RequestIdMiddleware).forRoutes({
path: '*',
method: RequestMethod.ALL, // 针对所有路由
})
}
}
- 取法
- req.headers'x-request-id'
- req.getRequestId()
- 引用 maya
import { RequestIdMiddleware } from 'node-maya'
const requestId = new RequestIdMiddleware().get()
日志使用
import { logger } from 'node-maya'
可以调用 logger 中的如下四个方法:
- info(message:string,options?: IOptions)
- debug(message:string,options?: IOptions)
- warn(message:string,options?: IOptions)
- error(message:Error,options?: IOptions)
IOptions 结构为:
interface IOptions {
module?: string; //模块名
requestId?: string; //请求 id
}
所有的日志文件会生成在 logs 目录下面,日志格式结构为:
- 终端显示:
[测试-debug] 2019-07-11T01:52:07.149Z [requestId]:null [file]:/Users/chenxu/Desktop/product/maya/src/utils/logger.spec.ts [msg]:测试Debug
- 日志文件记录:
{"time":"2019-07-11T02:55:56.442Z","level":"warn","server":"测试","file":"warn_Module","msg":"测试Warn","requestId":"xxxxId"}
拦截器 (interceptor)
- 请求时间记录
该组件如名字所示,会记录该次业务处理的时间,如接口相应时间超过 500ms,则以 warn 形式打印日志,需要优化,使用方式 (main.ts 全局引用):
import { RequestTimeInterceptor } from 'node-maya';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new RequestTimeInterceptor())//全局添加
await app.listen(3000, () => {});
}
错误类
Nest.js 有内置的错误类供开发人员使用,具体请看 但是对于企业来说,这些远远不够,所以组件库提供了 MayaException 额外的一些错误定义。具体实现如下:
export class MayaException extends Error {
statusCode: number;
constructor(code: number, msg?: any) {
super();
this.statusCode = code;
this.message = msg || errMsg[code];
}
}
export enum MayaErrorCode {
ParamsError = 10001,
RoleError = 10002,
}
const errMsg = {
10001: 'Param Error',
10002: 'Role Error',
};
后续如需添加,请联系组件库成员添加。
具体使用方法:
import { MayaException, MayaErrorCode } from 'node-maya'
throw new MayaException(MayaErrorCode.RoleError)
//或者 自定义消息
throw new MayaException(MayaErrorCode.ParamsError, 'some errors')
配置模块
maya 的配置模块使用的是 config 包,配置目录为根目录的 config 文件夹。定义是 json 文件。会根据 NODE_ENV 来自动读取不同的配置文件,例如 development,production,default。
因为 nest 的使用方式是模块化,所以在使用配置的时候应该是在需要的模块中使用。
Example(在 example 模块中使用 config):
- example.module.ts
import { Module } from '@nestjs/common'
import { ExampleController } from '../controller/index.controller'
import { ExampleService } from '../service/index.service'
import { ConfigModule } from 'node-maya'
/**
* 示例模块
*/
@Module({
imports: [ConfigModule],
controllers: [ExampleController],
providers: [ExampleService],
})
export class ExampleModule {}
- example.controller.ts
import { Controller, Get } from '@nestjs/common';
import { ExampleService } from '../service/index.service';
import { ConfigService } from 'node-maya';
@Controller('example')
export class ExampleController {
constructor(private readonly exampleService: ExampleService,
private readonly configService: ConfigService) { }
@Get('/big-data')
getBigData() {
return this.exampleService.getBigData();
}
@Get('/get-config')
getConfig() {
return this.configService.get('test');
}
}
- confg/development.json
{
"test": 123
}
导出 PDF
具体可参照 expamle/controller/example.controller.ts
导出 Excel
具体可参照 expamle/controller/example.controller.ts
框架化使用 Maya
直接上代码:
import { MayaServer } from 'node-maya'
import path from 'path'
MayaServer.start({
module: path.join(__dirname, 'module'), // 模块目录
port: 3000,
backend: 'http://127.0.0.1:3000',
static: {
pages: ['app.html'],
prefix: 'https://xx.com/core-hr/',
},
public: path.join(__dirname, 'public'),
sso: {
origin: 'xxx',
login: 'xxx',
logout: 'xxx',
},
interceptor: path.join(__dirname, 'interceptor'),
middle: path.join(__dirname, 'middleware'),
eureka: {
name: 'node-maya-test',
servers: ['http://192.168.0.113:8761/eureka/apps'],
},
})
加载 Redis
在 xxx.config 的配置文件中配置:
{
"redis": "redis://@127.0.0.1:6379/1",
}
加载加解密模块
注意,此模块开启,一定要使用 redis,否则不起作用。 在 xxx.config 的配置文件中配置:
{
"redis": "redis://@127.0.0.1:6379/1",
"isCrypt": true
}
加载签名模块
一旦加载签名模块,则全局接口都会默认验证 在 main.ts 中:
import { MayaServer } from '../src/index'
import path from 'path'
MayaServer.start({
isSign: true, //加载签名
})
加密流程使用说明
解密
Maya 底层已做解密处理,所以到接口层面的参数,都已经解密过。
加密 只需在接口层添加@SetEncryptFields() 的装饰器,里面写入加密字段即可。
demo:
import {
Controller,
Get,
Req,
Res,
Post,
UseGuards,
Delete,
Body,
UseInterceptors,
Query,
} from '@nestjs/common'
import { SignValidateGuard, SetEncryptFields } from 'node-maya'
import _ from 'lodash'
@Controller()
export class ExampleController {
constructor() {}
@Post('/api/example/decrypt')
@SetEncryptFields(['pwd', 'educationInfo']) // 需要加密字段
async decrypt() {
const data = {
userId: 1,
userName: '姓名',
pwd: '123456',
educationInfo: {
degree: '本科',
school: '北京大学',
},
}
return data
}
@Post('/api/example/decrypt/decrypt-array')
@SetEncryptFields([
'${index}.pwd',
'${index}.employees.${index}.employeeId',
'${index}.employees.${index}.employeeName',
])
async decryptArray() {
const data = [
{
userId: 1,
userName: '姓名 1',
pwd: '123456',
},
{
userId: 2,
userName: '姓名 2',
pwd: '236789',
},
{
userId: 3,
userName: '姓名 3',
pwd: 'abcdef',
employees: [
{
employeeId: '1',
employeeName: '张三',
},
{
employeeId: '2',
employeeName: '李四',
},
],
},
]
return data
}
@Post('/api/example/decrypt/decrypt-all')
@SetEncryptFields('all')
async decryptDataAll() {
return {
userId: 1,
userName: '姓名',
pwd: '123456',
}
}
}
ChangeLog 1.2.19
新增多 IP 转发
在配置文件中 (xxx.json) 添加 backendList 节点。
注意: 添加该配置后,原有的backend环境变量将失效。
推荐使用在xxx.json中配置路由转发。后期backend环境变量将不再支持。
"backendList": {
"/api/serverA": "http://127.0.0.1:3000",
"*": "http://127.0.0.1:3000" //默认转发配置
}
ChangeLog 1.3.0
新增多语言缓存
为了提高多语言获取效率,这次在 maya 中嵌入多语言接口。
该接口会采用缓存,缓存时间暂定 30min。
接口定义如下:
路由 | /api/multilingual | |
---|---|---|
请求方式 | get | |
请求参数 | ||
参数 | 是否必填 | 备注 |
product | 否 | 产品 id |
tenant | 否 | 租户 id |
classKey | 否 | |
resourceKey | 否 | |
cultures | 否 | 语言 |
Headers | ||
authorization | 是 | base64("{productCode},{tenantCode},89e25e99-3029-4add-844f-688f07a2481f") |
配置: 在对应环境变量的 config 文件中配置:
{
"multilingual": "https://localize.xx.com" //多语言访问域名
}
获取时间对比:
第一次请求
缓存请求
ChangeLog 1.3.7
- 默认转发不再依赖 backend
默认转发不再依赖 backend 环境变量。需要配置 config 文件 (另外 config 文件为 js,不再支持 json)。
支持多配置转发,1.3.0 版本的 backendList 也变动格式,为了支持路由修改定义 (pathRewrite 可选)
配置为:
"backendList": {
"/api/mobileCloud": {
target: 'https://app-test.xx.com',
pathRewrite: function (path) {
return path.replace("/api/mobileCloud", "");
}
},
"*": {
"target": "http://127.0.0.1:3000"
}
},
}
- 不推荐使用 requestFun
为了过渡,暂时兼容前版本 requestFun,因为 requestFun 取的还是 backend。后期迭代会剔除。
建议使用 requestForward。
ChangeLog 1.4.3
支持接收 post 请求的二进制数据
ChangeLog 1.4.4
修改包依赖关系
ChangeLog 1.4.5
graphql 接口支持签名
ChangeLog 1.4.6
解决转发 target 大小写 bug
changeLog 1.4.7
对接微信服务号
- 配置 (需要 redis 和服务号相关信息)
module.exports = {
redis: 'redis://:xxxx@47.101.76.214:19000/3',
wechat: {
appid: 'xxxx',
secret: 'xxxxx',
},
}
获取 token 接口
路由: /wechat/getToken 请求方式:Get 请求
发送模版消息方法
import { WechatService } from 'node-maya';
export class ExampleController {
constructor(
private readonly wechatService: WechatService
) { }
@Get('/api/send')
async sendTemplate() {
return this.wechatService.sendTemplate('otbf8v87ViGr98-Uz4BOo_wzw-BE',
'1ORAMytQvbUU1vWcKkwk6tgCXyL1x9DWW03klxy6R24',
'http://weixin.qq.com/download',
{
'appid': "wx6c5faa3cd75ec6d6",
'pagepath': "pages/my/index"
},
{})
}
}
对接小程序
- 配置 (需要 redis 和服务号相关信息)
module.exports = {
redis: 'redis://:xxxx@47.101.76.214:19000/3',
miniProgram: {
appid: 'xxxx',
secret: 'xxxxx',
},
}
获取 token 接口
路由: /miniProgram/getToken 请求方式:Get 请求
2.3.1
Maya 增加验证码验证函数 使用方法:
- 在 Module 引用
import { Module } from '@nestjs/common'
import { ExampleController } from '../controller/index.controller'
import { ExampleService } from '../service/index.service'
import { CaptchaModule } from 'node-maya'
/**
* 示例模块
*/
@Module({
imports: [CaptchaModule.forRoot('http://localhost:9801')], // forRoot 里面填写验证服务器的地址
controllers: [ExampleController],
providers: [ExampleService],
})
export class ExampleModule {}
- 调用 CaptchaService 里面的方法
import { CaptchaService } from 'node-maya'
export class ExampleController {
constructor(private readonly captchaService: CaptchaService) {}
@Post('/login')
async login(@Body() body: LoginDto) {
const res = await this.captchaService.captchaValidate(body.uuid, body.value); // 传入 uuid 和 value, true:验证通过 false:验证失败
if (res === false) {
throw new MayaException('login failure');
}
return true;
}
}
2.3.0
解决日志过大崩溃问题
2.2.35
redis 支持懒加载
2.2.33
修改 dockerfile && 支持版本信息
2.2.31
支持 cache 自定义 key
2.2.26 - 2.2.30
添加初始化日志
2.2.25
启动时添加环境变量和配置文件的日志,方便排查问题
2.2.21
redis 提供原生链接 以及 带有 preKey 的链接 两种方式
2.2.13-2.2.20
清理 node 包
2.2.13
添加 exclude 排除 mock 接口,另外改变引用方式,能通过 require 直接点击连接到文件
2.2.12
mock 支持数组,同个接口可以有多个 mock 数据,随机返回
2.2.10
修复拦截器 bug
2.2.9
拦截器添加 mock
2.2.1 - 2.2.8
postInstall 优化
2.1.31
优化@cache,不必传入参数
2.1.26 - 2.1.30
- 提供装饰器@cache
- 错误类 code 支持字符串,并添加第三个参数,是否是 httpCode
2.1.25
http 拦截器错误 throw 不包含路由
2.1.24
redis 初始化添加 log
2.1.22
redis 支持数组字符串
2.2.21
redis 换成 ioredis,支持 cluster 模式
2.1.19
添加 graphql,改写法
2.1.18
添加 nest-cli
2.1.17
postInstall 添加 dockerFile
2.1.16
初始化提取公用函数,简化代码
2.1.15
修改 xml 和 text 中间件顺序
2.1.14
美化错误堆栈信息 && xml 解析和 text 冲突 bug
2.1.4 - 2.1.13
底层 nest.js 升级大版本,修复 bug 及升级写法
2.1.3
- 添加 postInstall(eslint)
- 访问 html 添加 log 日志
2.0.1
更新拦截器,删除 header.host
2.0.0
- 添加 Http 请求拦截器,实现发送 http 请求拦截
用法:参考Maya中的Http请求
changeLog 1.4.8
新增微信获取用户接口
changeLog 1.4.9
修改签名验证逻辑
changeLog 1.5.0
支持 mysql
changeLog 1.5.1
修复支持 mysql
changeLog 1.5.2
支持获取 xml 数据
changeLog 1.5.4
微信公众号自定义菜单
changeLog 1.5.8
支持 skywalking
changeLog 1.6.0
添加热重启,tslint 执行 npm run nodemon 即可热重启
changeLog 1.6.1
日志添加 requestId(X-Correlation-ID) 发送请求添加拦截器
changeLog 1.6.3
升级 typescript
changelog 1.6.9
支持路由直接访问页面
MayaServer.start({
module: path.join(__dirname, 'module'),
port: 3001,
route: {
prefix: 'https://xx.com/points-web/',
redirect: [
{
page: 'login.html',
path: ['test'],
},
],
},
})
changelog 1.7.6
日志添加租户