1.0.4 • Published 1 year ago

xstao-common-util-server v1.0.4

Weekly downloads
-
License
ISC
Repository
-
Last release
1 year ago

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"))
    
}