IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    基于Egg.js二次封装框架,一键安装,干货上场

    羊先生发表于 2024-01-09 08:31:00
    love 0

    highlight: agate

    theme: fancy

    安装

    npm i egg-bag-framework

    内置多种模块,中间件以及工具

    源码地址,
    演示地址

    中间件

    校验sing签名是否合法,防止随意发起请求

    'use strict';
    module.exports = (option, app) => {
        return async function sing(ctx, next) {
            const sing = ctx.request.header.sing;
            const { domain, expireTime, cache } = ctx.app.config.website;
            const default_cache = 'redis';
            if (sing) {
                let getSing = null;
                if (cache === default_cache) {
                    getSing = await app.redis.get(sing);
                } else {
                    getSing = await app.lru.get(sing);
                }
                if (getSing) {
                    ctx.body = ctx.resultData({ msg: 'sing签名已过期' }); // 在存在说明既过期
                } else {
                    try {
                        const decSing = ctx.helper.aesDecrypt(sing);
                        const singData = JSON.parse(decSing);
                        if (singData.domain === domain) {
                            if (cache === default_cache) {
                                await app.redis.set(sing, 1);
                            } else {
                                await app.lru.set(sing, 1);
                            }
                            await app.redis.set(sing, 1);
                            await app.redis.expire(sing, expireTime);
                            await next();
                        } else {
                            ctx.body = ctx.resultData({ msg: 'sing签名不合法,缺少字符串' });
                        }
                    } catch (e) {
                        ctx.body = ctx.resultData({ msg: 'sing签名不合法' });
                    }
                }
            } else {
                ctx.body = ctx.resultData({ msg: '缺少sing签名' });
            }
        };
    };

    限流中间件

    防止接口被恶意盗刷,如果被攻击了,请求使用nginx或者服务器配置白黑名单

    'use strict';
    const { RateLimiterMemory } = require('rate-limiter-flexible'); // 限流中间件
    module.exports = () => {
        // 创建一个基于内存的令牌桶速率限制器,每秒限制 12 次请求
        const opts = {
            points: 12,
            duration: 1,
        };
        const rateLimiter = new RateLimiterMemory(opts);
        return async function limiter(ctx, next) {
            rateLimiter.consume(ctx.request.ip)
                .then(rateLimiterRes => {
                    next();
                })
                .catch(rateLimiterRes => {
                    ctx.body = ctx.resultData({ msg: '触发限流了', code: 2001 });
                });
        };
    };

    验证jwt

    'use strict';
    
    module.exports = () => {
        return async function authority(ctx, next) {
            const authorization = ctx.request.header.authorization;
            if (authorization) {
                try {
                    ctx.helper.verifyToken(authorization); // 验证jwt
                    await next();
                } catch (err) {
                    ctx.body = ctx.resultData({ msg: 'access_token过期', code: 1003 });
                }
            } else {
                ctx.body = ctx.resultData({ msg: '缺少access_token', code: 1003 });
            }
        };
    };

    内置模块

    jwt

    (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的

    // plugin.js
    exports.jwt = {  
        enable: true,  
        package: 'egg-jwt',  
    };
    // config.default.js
    config.jwt = {  
        secret: 'ABCD20231017QWERYSUNXSJL', // 可以自定义  
        sign: {  
            expiresIn: 8 * 60 * 60, // 过期时间8小时  
        },  
    };

    Validate

    参数校验模块

    // plugin.js
    exports.validate = {  
        enable: true,  
        package: 'egg-validate',  
    };
    // config.default.js
    config.validate = {  
        convert: true,  
        translate() {  
            const args = Array.prototype.slice.call(arguments);  
            return I18n.__.apply(I18n, args);  
        },  
    };

    redis

    Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理

    // plugin.js
    exports.redis = {  
        enable: true,  
        package: 'egg-redis',  
    };
    // config.default.js
    config.redis = {  
        client: {  
            port: 6379,  
            host: '127.0.0.1',  
            password: 'auth',  
            db: 0,  
        },  
    }

    lru

    本地缓存

    exports.lru = {  
        enable: true,  
        package: 'egg-lru', // 本地缓存  
    };
    config.lru = {  
        client: {  
            max: 3000, // 所有lru缓存配置可用  
            maxAge: 1000 * 60 * 30, // 60 min cache  
        },  
        app: true, // 加载到app中,默认是打开的  
        agent: false, // 加载到代理中,默认为关闭  
    };

    上传模式

    // config.default.js
    config.multipart = {  
        mode: 'file',  
        fileSize: '50mb', // 接收文件大小  
        whitelist: [ // 允许接收的文件类型  
            '.png',  
            '.jpg',  
            '.webp',  
            '.gif',  
            '.zip',  
            '.doc',  
            '.docx',  
            '.txt',  
            '.xlsx',  
            '.pdf',  
            '.mp4',  
            '.webm',  
            '.mov',  
            '.flv',  
            '.avi',  
            '.f4v',  
            '.mov',  
            '.m4v',  
            '.rmvb',  
            '.rm',  
            '.mpg',  
            '.mpeg',  
        ],  
    };

    Sequelize

    Sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能

    // plugin.js
    exports.sequelize = {  
        enable: true,  
        package: 'egg-sequelize',  
    };
    config.sequelize = {  
        dialect: 'mysql',  
        database: 'pm_webleading',  
        host: '127.0.0.1',  
        port: '3306',  
        username: 'pm_webleading',  
        password: '123456',  
        underscored: false,  
        timezone: '+08:00',  
        define: {  
            timestamps: true,  
            freezeTableName: true,  
        },  
    };

    Mysql

    MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一

    // plugin.js
    exports.mysql = {  
        enable: true,  
        package: 'egg-mysql',  
    };
    // config.default.js
    config.mysql = {  
        client: {  
        // host  
        host: '127.0.0.1',  
        // 端口号  
        port: '3306',  
        // 用户名  
        user: 'pm_webleading',  
        // 密码  
        password: '123456',  
        // 数据库名  
        database: 'pm_webleading',  
        },  
        // 是否加载到 app 上,默认开启  
        app: true,  
        // 是否加载到 agent 上,默认关闭  
        agent: false,  
    };

    内置工具

    已挂在egg.js,ctx对象上调用方法如下

    'use strict';  
      
    const {Controller} = require('egg');  
      
    class HomeController extends Controller {  
        async index() {  
           const {ctx} = this;  
            try {  
                for (const file of ctx.request.files) {  
                   const filePath = await ctx.helper.uploadLocaFile({file})  // cxt.helper.xxxx
                }  
            } finally {  
               await ctx.cleanupRequestFiles();  
            }  
        }
    }
    module.exports = HomeController;

    上传文件本地

    可以上传以上配置类型的文件

    uploadLocaFile({ file, filePath }) {  
        const { ctx } = this;  
        return new Promise(async (resolve, reject) => {  
            try {  
                const filename = file.filename;  
                const extname = path.extname(filename);  
                const _filePath = filePath || `public/upload/${ctx.helper.nanoid()}${extname}`;  
                const localPath = path.join(ctx.app.baseDir, 'app', _filePath);  
                // 读取文件  
                const source = fs.createReadStream(file.filepath);  
                // 创建写入流  
                const target = fs.createWriteStream(localPath);  
                await pump(source, target);  
                resolve(_filePath);  
            } catch (err) {  
                reject(err);  
            }  
        });  
    }

    上传图片-带压缩

    只能上传图片

    uploadLocalImage({ file, filePath, width = 500, quality = 75 }) {
            const { ctx } = this;
            const extname = path.extname(file.filename);
            const _filePath = filePath || `public/image/${ctx.helper.nanoid()}${extname}`;
            const localPath = path.join(ctx.app.baseDir, 'app', _filePath);
            return new Promise((resolve, reject) => {
                Jimp.read(file.filepath)
                    .then(image => {
                        image.resize(width, Jimp.AUTO)
                            .quality(quality)
                            .write(localPath);
                        resolve(_filePath);
                    })
                    .catch(err => {
                        reject(err);
                    });
            });
        }

    对称加密

    aesEncrypt(data, options) {
            options = Object.assign({ key: this.app.config.website.key, iv: this.app.config.website.iv }, options);
            let str = data;
            if (typeof data === 'object') {
                str = JSON.stringify(data);
            }
            str = CryptoJS.enc.Utf8.parse(str);
            const crypto = CryptoJS.AES.encrypt(str, CryptoJS.enc.Utf8.parse(options.key), {
                iv: CryptoJS.enc.Utf8.parse(options.iv),
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.Pkcs7,
            });
            return crypto.toString(); // 对称加密内容
        },

    对称解密

    aesDecrypt(data, options) {
            options = Object.assign({ key: this.app.config.website.key, iv: this.app.config.website.iv }, options);
            const decrypt = CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse(options.key), {
                iv: CryptoJS.enc.Utf8.parse(options.iv),
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.Pkcs7,
            });
            return CryptoJS.enc.Utf8.stringify(decrypt); // 对称解密内容
        },

    非对称加密

     encrypt(str, options) {
            options = Object.assign({ publicKey: this.app.config.website.publicKey }, options);
            const encrypted = new JSEncrypt();
            encrypted.setPublicKey(options.publicKey.toString());
            return encrypted.encrypt(str); // 非对称加密字符串
        },

    非对称解密

    decrypt(str, options) {
            options = Object.assign({ privateKey: this.app.config.website.privateKey }, options);
            const decrypted = new JSEncrypt(); // 创建解密对象实例
            decrypted.setPrivateKey(options.privateKey.toString()); // 设置私钥
            return decrypted.decrypt(str); // 非对称解密内容
        },

    md5加密

    md5(data) {
            let str = data;
            if (typeof data === 'object') {
                str = JSON.stringify(data);
            }
            return CryptoJS.MD5(str)
                .toString();
        },

    随机ID

    nanoid(size = 12) {
            const nanoid = customAlphabet(alphabet.join(''), size);
            if (size >= 12) {
                return dayjs()
                    .format('YYYYMMDD') + nanoid(); // 获取不重复随机ID
            }
            return nanoid(); // 获取重复随机ID
    
        },

    jwt-生成token-校验token

    generateToken(data) {
            return this.app.jwt.sign(data, this.app.config.jwt.secret); // 生成token
        },
        verifyToken(token) {
            return this.app.jwt.verify(token, this.app.config.jwt.secret); // 验证token
        },


沪ICP备19023445号-2号
友情链接