1.0.4 • Published 1 year ago
xstao-common-util-server v1.0.4
xstao-common-util-server
xstao-common-util-server是一个公司后端通用库,包含一些nodejs通用的方法
安装方法
npm install xstao-common-util-server --save
CustomError-自定义异常
- API
declare module CustomError {
// 自定义异常格式,符合公司内部http返回值规范 http://aiki.avalongames.com:8090/pages/viewpage.action?pageId=8159346
interface CustomErrorInterface {
httpStatusCode: number
status: number
}
// 抛出自定义异常
function throwCustomError(error: CustomErrorInterface): void
// 解析自定义异常
function parseCustomError(e: any): CustomErrorInterface
}
- Demo
import { CustomError } from 'xstao-common-util-server'
const { parseCustomError,throwCustomError } = CustomError
try {
// todo
// 抛出自定义异常
throwCustomError({ httpStatusCode: 500, status: xxx })
} catch (e) {
// 解析自定义异常
const { httpStatusCode = 500, status = 1002 } = parseCustomError(e)
response({ ctx, data: {}, httpStatusCode, status })
}
CustomLog-自定义日志
- API
// 对winstonjs/winston进行二次封装
declare class CustomLog {
constructor(config: {
// 日志logger名称,对应输出的文件名前缀
names: Array<string>
// 日志输出路径
path: string
// 日志等级
level?: string
})
// 输出日志
log(jsonParam: {
// 日志logger名称
logger: string
// 日志等级
level?: string
// 输出的消息
message: string
}): void
}
- Demo
// 初始化日志
global.logger = new CustomLog({ names: ['server', 'business'], path: 'log', level: 'info' })
global.logger.log({ logger: 'server',level:'info', message: '服务器初始化完成' })
CustomMysql-自定义mysql
- API
import { PoolConfig, FieldInfo, Connection } from 'mysql'
// mysq初始化的配置
export interface CustomMysqlConfig extends PoolConfig {
// 主机名
host: string
// 端口
port: number
// 用户名
user: string
// 密码
password: string
// 库名
database: string
}
// sql命令
export type SqlCommand = string | Array<string>
// 查询函数,可用于事务内执行
export type Query = (jsonParam: {
connection: Connection
sqlCommand: SqlCommand
}) => Promise<
Array<{
// 执行结果
rows: Array<any> | any
// 字段
fields: Array<FieldInfo>
}>
>
// 对mysqljs/mysql进行二次封装
declare class CustomMysql {
// 配置中的字符集默认为utf8mb4
constructor(config: CustomMysqlConfig)
// 执行sql
excute(jsonParam: {
// sql命令
sqlCommand: SqlCommand
// 是否以事务执行
transaction: boolean
}): Promise<
Array<{
// 执行结果
rows: Array<any> | any
// 本次执行的sql命令
sqlCommand: string
// 字段
fields: Array<FieldInfo>
}>
>
// 在事务内部执行sql,返回是否执行成功,不会抛出异常
relyTransaction(
execFn: (jsonParam: {
// 查询函数
query: Query
// mysqljs的连接
connection: Connection
}) => Promise<void>
): Promise<boolean>
// 加载版本管理工具(注意:该方法不做异常捕获)
// 对程序自身的mysql数据库进行版本管理,代替运维操作,只适用于数据量较小的库;
// 原理:创建一个sql更新记录的table,每次启动服务器时对比sql文件和历史记录,如果是新sql则执行更新;如果库里面没有任何表,并且xxx.sql文件存在,则执行xxx.sql对表结构进行初始化
loadVersionManager(jsonParam: {
// sql文件目录
sqlDir: string
// 数据库的开发名(区分运维部署时的实际名称),作为sql文件名前缀
databaseDevName: string
}): Promise<void>
// 检查乐观锁的版本号
checkOptimismLockVersion(jsonParam: {
// 表名
table: string
// 该行数据的主键(主键字段必须为id)
id: string | number
// 版本号
version: string
// 记录乐观锁的字段名,默认为version
lockColumnKey?: string
}): Promise<void>
// 更新乐观锁的版本号
updateOptimismLockVersion(jsonParam: {
// 表名
table: string
// 该行数据的主键(主键字段必须为id)
id: string | number
// 记录乐观锁的字段名,默认为version
lockColumnKey?: string
}): Promise<void>
}
export { CustomMysql }
- Demo
// 普通场景
global.mysql = new CustomMysql({
host: 'xx.xx.xx.xx',
port: 3306, user: 'xx',
password: 'xx',
database: 'xx'
})
const [{ rows }] = await global.mysql.excute({
sql: `select * from table`,
transaction: false,
})
// mysql版本管理器
global.mysql = new CustomMysql({
host: 'xx.xx.xx.xx',
port: 3306,
user: 'xx',
password: 'xx',
database: 'xx' ,
multipleStatements:true
})
await global.mysql.loadVersionManager({sqlDir:"xxx",databaseDevName:"xxx"})
// 事务内执行
const isSuccess = await mysql.relyTransaction(
async ({ query, connection }) => {
const [{ insertId }] = await query({
connection,
sqlCommand: `insert into account set id=10,name='xx'`,
})
await query({
connection,
sqlCommand: [
`insert into account set id=11,name='${insertId}'`,
`insert into account set id=12,name='${insertId}'`,
],
})
}
)
console.log(isSuccess)
CustomRedis-自定义redis
- API
import { ClientOpts } from 'redis'
// 对NodeRedis/node_redis进行二次封装
declare class CustomRedis {
// 配置中的detect_buffers默认为true
constructor(config: ClientOpts)
// 执行命令
excute(jsonParam: {
// 数据库序号
index?: number
// 参数
params: any
// 命令
command: string
}): Promise<any>
// 上锁
lockByRedis(jsonParam: {
// 数据库序号
index?: number
// 锁的key名
lockKey: string
}): Promise<void>
// 解锁
unlockByRedis(jsonParam: {
// 数据库序号
index?: number
// 锁的key名
lockKey: string
}): Promise<void>
// 使用redis锁保证逻辑的隔离性
doAtomicFuncByLock(jsonParam: {
// 数据库序号
index?: number
// 锁的key名,支持多个锁
lockKey: string | Array<string>
// 锁中间执行的逻辑,常用于并发操作
atomicFunc: () => any
}): Promise<any>
}
export { CustomRedis }
- Demo
// 普通场景
global.redis = new CustomRedis({
host: 'xx.xx.xx.xx',
port: 3306,
password: 'xx',
db:xx
})
file-文件操作
- API
declare module file {
function download(jsonParam: {
// 源文件的下载地址
url: string
// 文件存放路径
filePath: string
// 文件编码,默认为utf8
encoding?: string
}): Promise<void>
}
export { file }
- Demo
// 文件下载
const {file} = require("xstao-common-util-server")
file.download({url:'xxx',path:'temp'})
koaUtil-koa工具
- API
import { Context, Middleware } from 'koa'
import * as Router from 'koa-router'
declare module koaUtil {
// 判断服务器是否初始化完成
function checkInitRouter(
// 检查函数
checkFunc: () => boolean
): Router
// 检查md5签名
function checkMd5SignMiddleware(
// md5签名的key
md5Key: string
): Middleware
// 防盗链检测
function checkRefererMiddleware(
// 访问来源,支持多个
referer: string | Array<string>
): Middleware
// iam权限认证,返回一个中间件
function iamMiddleware(jsonParam: {
// iam服务地址
iamServiceUrl: string
// opweb应用令牌
projectToken: string
// 路由匹配类型,默认为matchedRoute
type?:
| 'matchedRoute' // 匹配的路由,包含通配符,即上下文中的_matchedRoute
| 'path' // 实际请求路径,即上下文中的path
| 'custom' // 自定义路由,值由customRouteFunction参数决定
// 自定义路由,仅type='custom'生效
customRouteFunction?: (
ctx: Context // 上下文
) => string
// 动作
action: string
// 通用信息限制,默认自动从请求中获取所有参数,get从query string获取,其他从body中获取
objectAttr?:
| Array<string> // 手动指定通用信息限制的key
| ((ctx: Context) => { [propName: string]: any }) // 从上下文中自定义
}): Middleware
// iam工具
const iamUtil: {
// 从iam服务获取用户授权
getUserAuthorization: (jsonParam: {
// iam服务地址
iamServiceUrl: string
// 上下文
ctx: Context
}) => Promise<{
// 用户id
id: number
}>
}
// 参数类型检查支持的类型
type paramTypeString =
| 'number'
| 'string'
| 'object'
| 'any'
| 'Array<number>'
| 'Array<string>'
| 'Array<object>'
| 'Array<any>'
// 参数类型实例
const paramType: paramTypeString
// 参数格式化
const paramFormat: {
// 参数类型检查
checkType: (jsonParam: {
// 值
value: any
// 类型
type: paramTypeString
}) => void
// 参数检查并格式化,返回一个中间件
paramFormatMiddleware: (
// 格式
formats: Array<{
// 参数key
id: string
// 正则
regex?: RegExp
// 类型
type: paramTypeString
// 是否可选,默认为必传
optional?: boolean
}>
) => Middleware
}
// 格式化所有get请求中的参数,url解码
const queryFormatRouter: Router
// 按公司内部返回值规范返回
function response(jsonParam: {
// 上下文
ctx: Context
// http状态码
httpStatusCode: number
// 业务状态码
status: number
// 业务数据
data?: any
}): void
}
export { koaUtil }
- Demo
// checkInitRouter 应用初始化检测路由,可在服务器未初始化完成前不提供业务接口访问
app.use(checkInitRouter(global.hasInitialized).routes())
.use(checkInitRouter(global.hasInitialized).allowedMethods())
// checkMd5SignMiddleware md5签名检测中间件
const v1 = new Router({
prefix: '/xx',
})
v1.get('/xx-xx-xx', checkMd5SignMiddleware(global.md5Key))
// checkRefererMiddleware 防盗链检测中间件
const v1 = new Router({
prefix: '/xx',
})
v1.get('/xx-xx-xx', checkRefererMiddleware(global.referer))
// iamMiddleware IAM权限认证中间件
const v1 = new Router({
prefix: '/xx',
})
v1.post('/xx-xx-xx',iamMiddleware({ iamServiceUrl: 'xx', projectToken: 'xx', type: 'path', action: 'xx' }))
// iamUtil
const { id } = await getUserAuthorization({ iamServiceUrl: 'xx', ctx:ctx })
// paramFormatMiddleware 参数格式化中间件
const v1 = new Router({
prefix: '/xx',
})
v1.get('/xx-xx-xx', paramFormatMiddleware([{id:"id",regex:/^\d+$/,type:'Array<number>',optional:true}]))
// queryFormatRouter get请求参数格式化路由,将所有get参数的值进行url解码
app.use(queryFormatRouter.routes()).use(queryFormatRouter.allowedMethods())
// response 返回客户端消息
response({ ctx, httpStatusCode: 500, status: 50001, data })
system-系统层面的工具
- API
declare module system {
// 不使用缓存重新加载模块
function requireUncached(module: string)
}
export { system }
- Demo
const {system: {requireUncached}} = require("xstao-common-util-server")
const path = require("path")
const doSomeThing = ()=>{
//此处只能使用相对路径
const m = requireUncached(path.resolve(__dirname, "../xxx/xxx"))
}