public-sdk
v2.3.1
Published
Node.js 服务端通用工具库 - 提供微信小程序 SDK、统一响应封装、常用工具方法等
Maintainers
Readme
公共服务 SDK
版本: 2.3.0 | Node.js: >= 14.0.0
Node.js 服务端通用工具库,提供微信小程序 SDK、统一响应封装、常用工具方法等。
✨ 特性
- 🔐 安全可靠:使用 Node.js crypto 模块生成安全的随机数和 UUID
- 🛡️ 类型安全:完善的参数验证和类型检查
- 🧪 测试覆盖:47+ 单元测试用例,100% 方法覆盖率
- 📦 零依赖:除 axios 外无其他第三方依赖
- 🚀 即插即用:ES Module 支持,Tree-shaking 友好
📦 安装
npm install public-sdk🚀 快速开始
微信小程序 SDK
import { WX } from "public-sdk";
const wx = new WX({
appid: "your-appid",
secret: "your-secret",
env_version: "develop", // develop | trial | release
});
// 获取 access_token
const token = await wx.getAccessToken();
// 获取微信 openid
const openid = await wx.getOpenid(code);
// 获取小程序码
const qrBuffer = await wx.getUnlimitedQRCode({
page: "pages/index/index",
scene: "user=123",
width: 430,
});
// 敏感词检测
const result = await wx.checkSensitiveWords(text, openid);
// 获取手机号
const phoneInfo = await wx.getPhoneNumber(code);响应数据统一封装
import { Send } from "public-sdk";
// 自定义成功响应 code(默认为 0)
Send.successCode = 200;
// 成功响应
Send.success(data); // { code: 0, data, message: 'success' }
// 错误响应
Send.fail("操作失败", 400); // { code: 400, message: '操作失败', data: null }
// 格式化错误信息
Send.formatError(error);
// 操作过于频繁响应
Send.tooManyRequests(); // { code: 429, message: '请求过于频繁' }🔧 工具类 Utils
import { Utils } from "public-sdk";UUID 生成
使用 crypto.randomUUID() 生成符合 RFC 4122 标准的 UUID v4。
const uuid = Utils.uuid();
// 示例输出: "550e8400-e29b-41d4-a716-446655440000"特性:
- 使用加密安全的随机数生成器
- 保证唯一性
- 标准 UUID 格式(36 字符)
格式化方法
formatAccount(account)
格式化账号:转小写 + 去除首尾空格
Utils.formatAccount(" [email protected] ");
// 返回: "[email protected]"
Utils.formatAccount(null); // 返回: ""
Utils.formatAccount(undefined); // 返回: ""
Utils.formatAccount(12345); // 返回: "12345"formatPassword(password)
格式化密码:去除首尾空格
Utils.formatPassword(" myPassword123 ");
// 返回: "myPassword123"
Utils.formatPassword(null); // 返回: ""
Utils.formatPassword(undefined); // 返回: ""随机字符串生成
randomStr(len?, prefix?, charset?)
生成加密安全的随机字符串。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| len | number | 8 | 生成的字符串长度 |
| prefix | string | '' | 前缀 |
| charset | string | 'alphanumeric' | 字符集类型 |
字符集选项:
| 值 | 说明 | 包含字符 |
|----|------|----------|
| 'alphanumeric' | 字母数字混合(默认) | a-z, A-Z, 0-9 |
| 'alpha' | 纯字母 | a-z, A-Z |
| 'numeric' | 纯数字 | 0-9 |
示例:
// 默认:8 位字母数字混合
Utils.randomStr();
// 示例: "aB3xK9mP"
// 自定义长度
Utils.randomStr(16);
// 示例: "qR7tY2wE8pL1kO3j"
// 带前缀
Utils.randomStr(8, "token_");
// 示例: "token_xKmPqR"
// 纯字母
Utils.randomStr(20, "", "alpha");
// 示例: "aBcDeFgHiJkLmNoPqRsT"
// 纯数字
Utils.randomStr(6, "", "numeric");
// 示例: "385921"特性:
- 使用
crypto.randomBytes()生成密码学安全的随机数 - 支持自定义字符集
- 可用于生成 token、验证码、临时密码等场景
校验方法
isEmail(email)
校验邮箱格式是否符合 RFC 标准。
Utils.isEmail("[email protected]"); // true
Utils.isEmail("[email protected]"); // true
Utils.isEmail("invalid-email"); // false
Utils.isEmail(null); // false
Utils.isEmail(""); // false支持的邮箱格式:
- 标准格式:
[email protected] - 带子域名:
[email protected] - 带特殊字符:
[email protected] - 多级 TLD:
[email protected]
isPhone(phone, strict?)
校验手机号格式。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| phone | string \| number | - | 手机号 |
| strict | boolean | true | 是否使用严格模式 |
严格模式(默认):
- 仅支持中国大陆手机号
- 格式:11 位数字,1 开头,第二位为 3-9
Utils.isPhone("13812345678"); // true
Utils.isPhone("19900001111"); // true
Utils.isPhone("12345678901"); // false (号段无效)
Utils.isPhone("1381234567"); // false (位数不足)
Utils.isPhone(13812345678); // true (支持数字类型)宽松模式:
- 支持国际手机号格式
- 格式:可选 + 前缀,7-15 位数字
Utils.isPhone("+8613812345678", false); // true
Utils.isPhone("+11234567890", false); // true
Utils.isPhone("8613812345678", false); // trueisUrl(url)
校验 URL 格式是否有效。
Utils.isUrl("https://www.example.com"); // true
Utils.isUrl("http://test.org/path?query=1"); // true
Utils.isUrl("ftp://files.server.com"); // true
Utils.isUrl("not-a-url"); // false
Utils.isUrl("http://"); // false
Utils.isUrl(null); // false特性:
- 使用原生
URL构造函数进行验证 - 支持 http、https、ftp 等协议
- 自动处理各种 URL 格式
数据转换
list2tree(items, prop?)
将扁平列表转换为树形结构(支持多级嵌套)。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| items | Array | - | 扁平数据列表 |
| prop | Object | {} | 属性名配置 |
默认配置:
{
id: 'id', // ID 字段名
parent_id: 'parent_id', // 父级 ID 字段名
children: 'children', // 子节点字段名
label: 'label', // 显示文本字段名
value: 'value' // 值字段名
}基本用法:
const items = [
{ id: 1, name: "根节点1", parent_id: 0 },
{ id: 2, name: "子节点1-1", parent_id: 1 },
{ id: 3, name: "子节点1-2", parent_id: 1 },
{ id: 4, name: "根节点2", parent_id: 0 },
{ id: 5, name: "子节点2-1", parent_id: 4 },
];
const tree = Utils.list2tree(items, { label: "name" });
// 输出:
[
{
id: 1,
name: "根节点1",
label: "根节点1",
value: 1,
children: [
{
id: 2,
name: "子节点1-1",
label: "子节点1-1",
value: 2,
parent_name: "根节点1",
children: []
},
// ...
]
},
// ...
]自定义属性名:
const items = [
{ itemId: 1, title: "根节点", parentId: null },
{ itemId: 2, title: "子节点", parentId: 1 },
];
const tree = Utils.list2tree(items, {
id: "itemId",
label: "title",
value: "itemId",
parent_id: "parentId"
});Sequelize 兼容性:
自动识别 Sequelize 模型实例,提取 dataValues。
const sequelizeItems = await Model.findAll();
const tree = Utils.list2tree(sequelizeItems);
// 自动处理 Sequelize 实例特性:
- ✅ 支持多级嵌套
- ✅ 自动跳过重复 ID 的项(控制台警告)
- ✅ 处理 null/undefined 的父级 ID(视为根节点)
- ✅ 自动添加
parent_name字段 - ✅ 空数组/非数组输入返回空数组
路由匹配
isInRoutes(route, routes)
检查 API 路由是否在匹配列表中(支持路径参数)。
参数:
| 参数 | 类型 | 说明 |
|------|------|------|
| route | { method: string, path: string } | 待匹配的路由 |
| routes | Array<{ method: string, path: string }> | 路由匹配列表 |
示例:
const routes = [
{ method: "GET", path: "/api/users" },
{ method: "GET", path: "/api/users/:id" },
{ method: "POST", path: "/api/users" },
];
// 精确匹配
Utils.isInRoutes({ method: "GET", path: "/api/users" }, routes);
// true
// 路径参数匹配
Utils.isInRoutes({ method: "GET", path: "/api/users/123" }, routes);
// true
// HTTP 方法不区分大小写
Utils.isInRoutes({ method: "get", path: "/api/users" }, routes);
// true
// 不匹配
Utils.isInRoutes({ method: "POST", path: "/api/posts" }, routes);
// false特性:
- ✅ 支持路径参数(如
/users/:id) - ✅ HTTP 方法不区分大小写
- ✅ 路径不区分大小写
- ✅ 安全的 null 输入处理
IP 地址获取
clientIp(req)
从请求对象中获取客户端真实 IP 地址。
参数:
| 参数 | 类型 | 说明 |
|------|------|------|
| req | Object | Express/Koa 等 HTTP 请求对象 |
IP 获取优先级:
X-Forwarded-For头(取第一个 IP)X-Real-IP头req.ipreq.connection.remoteAddressreq.socket.remoteAddress
示例:
// Express 路由中使用
app.get("/api/data", (req, res) => {
const ip = Utils.clientIp(req);
console.log(ip); // "192.168.1.1"
});特性:
- ✅ 处理代理服务器的多级转发
- ✅ 自动移除 IPv6 映射前缀 (
::ffff:) - ✅ 将 IPv6 localhost (
::1) 转换为127.0.0.1 - ✅ 处理逗号分隔的多个 IP
- ✅ 支持数组类型的 header
- ✅ 空 req 对象返回空字符串
典型应用场景:
// Nginx 反向代理配置
// nginx.conf: proxy_set_header X-Real-IP $remote_address;
// proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
app.use((req, res, next) => {
const clientIp = Utils.clientIp(req);
req.clientIp = clientIp; // 挂载到 req 上
next();
});🧪 测试
运行测试套件:
npm test
# 或
node test.js测试覆盖:
- ✅ UUID 生成(3 个用例)
- ✅ 格式化方法(7 个用例)
- ✅ 随机字符串(6 个用例)
- ✅ 邮箱校验(3 个用例)
- ✅ 手机号校验(5 个用例)
- ✅ URL 校验(3 个用例)
- ✅ 列表转树形结构(7 个用例)
- ✅ 路由匹配(5 个用例)
- ✅ 客户端 IP 获取(8 个用例)
总计:47 个测试用例,全部通过 ✅
📝 更新日志
[2.3.0] - 2026-04-30
✨ 新功能
- 🔐 使用
crypto模块替代Math.random()提升安全性 - 🎲
randomStr()新增charset参数支持自定义字符集 - 📱
isPhone()新增strict参数支持国际号码格式
🐛 Bug 修复
- ✅ 修复
uuid()生成算法错误(toString(32) → toString(16)) - ✅ 修复
list2tree()重复 ID 导致节点重复添加的问题 - ✅ 修复
isInRoutes()传入 null 时解构错误
💎 优化改进
- 📧 优化邮箱正则表达式,支持更多 RFC 标准格式
- 📱 优化手机号正则表达式,支持最新号段
- 🌐 使用原生
URL构造函数替代正则校验 URL - 🌳 增强
list2tree()健壮性(空值处理、重复检测) - 🛡️ 完善所有方法的类型安全检查和参数验证
- 🖥️ 增强
clientIp()对各种代理场景的支持
🧪 测试
- 🆕 新增完整测试套件(47 个测试用例)
- ✅ 100% 公共方法覆盖率
- ✅ 包含正向/负向测试、边界情况测试
[1.0.1] - 2025-09
- 初始版本发布
📄 许可证
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📞 支持
如有问题或建议,请提交 Issue
