兼容易支付(epay)协议的 Node.js 聚合支付系统
初衷:易支付代码业务逻辑不严谨,经常掉单。替换成 GoPay 后基本 0 掉单!
- ✅ 兼容易支付协议,源站无需改动
- ✅ 支付宝:PC 网站支付、手机网站支付
- ✅ 微信支付:H5 支付、Native 扫码
- ✅ 多通道负载均衡(随机选取)
- ✅ UA 自动识别终端类型
- ✅ 订单标题自动重写(防风控)
- ✅ 启动校验:仅启用配置完整的通道
- ✅ 数据库:SQLite(默认)/ MySQL / PostgreSQL
# 安装依赖
npm install
# 开发模式(热重载)
npm run dev
# 生产模式
node app.js
# 或使用 PM2 守护进程
pm2 start app.js --name=gopay服务默认监听 127.0.0.1:3000
编辑 config.js:
module.exports = {
web: {
payUrl: "https://pay.example.com", // 支付域名,用于回调通知
},
user: {
10001: { key: "商户密钥" }, // PID → KEY 映射
},
alipay: [
{
appId: "20210001xxxx",
privateKey: "应用私钥",
alipayPublicKey: "支付宝公钥",
},
],
wxpay: [
{
appId: "wx1234567890",
mchid: "1234567890",
privateKey: fs.readFileSync("./cert/wxpay/apiclient_key.pem"),
serial: "证书序列号",
secret: "APIv3密钥",
certs: { 平台证书序列号: fs.readFileSync("./cert/wxpay/platform.pem") },
only_native: false, // true 则强制扫码模式
},
],
form: {
subject: { rewrite: true, text: ["商品A", "商品B"] }, // 随机标题防风控
body: { rewrite: true, text: "商品描述" },
},
db: {
dialect: "sqlite", // sqlite | mysql | postgres
sqlite: { storage: "./data/gopay.db", logging: false },
mysql: { host: "127.0.0.1", database: "gopay", username: "", password: "" },
postgres: { host: "127.0.0.1", port: 5432, database: "gopay", username: "", password: "" },
},
};重要:
- 支付通道所有必填字段必须完整配置,否则该通道会被忽略
- 微信证书需提前通过
wxpay crt命令获取
cd ./node_modules/.bin
wxpay crt -m {mchid} -s {serial} -f {privateKey.pem} -k {secret} -o将输出的证书文件放入 ./cert/wxpay/ 目录。
| 接口 | 方法 | 说明 |
|---|---|---|
/submit.php |
POST | 下单入口(易支付协议兼容) |
/api/order_status |
GET | 订单状态查询 |
/pay/alipay_notify |
POST | 支付宝异步回调 |
/pay/alipay_return |
GET | 支付宝同步返回 |
/pay/wxpay_notify/:appid |
POST | 微信支付异步回调 |
/pay/wxpay/native |
GET | 微信扫码支付页面 |
/go |
GET | 支付跳转中间页 |
gopay/
├── app.js # 入口:插件/路由注册、axios拦截器
├── config.js # 全局配置(⚠️ 含敏感信息)
├── plugins/ # Fastify 插件
│ ├── alipay.js # 支付宝 SDK 封装
│ ├── wxpay.js # 微信支付 SDK 封装
│ ├── database.js # Sequelize + Order 模型
│ ├── user.js # 商户 PID 查询
│ └── constans.js # 响应码常量
├── routes/ # API 路由
│ ├── submit.js # 核心下单入口
│ ├── order.js # 订单查询
│ ├── redirect.js # 跳转中间页
│ └── pay/ # 支付回调
├── utils/ # 工具函数
│ ├── stringutils.js # 签名/UA检测
│ └── epayutils.js # 回调URL构建
├── templates/ # EJS 视图
├── public/assets/ # 静态资源
└── cert/wxpay/ # 微信证书(.gitignore)
| 组件 | 版本 | 说明 |
|---|---|---|
| Fastify | 5.x | Web 框架 |
| Sequelize | 6.x | ORM |
| alipay-sdk | 4.x | 支付宝 SDK |
| wechatpay-node-v3 | 2.x | 微信支付 v3 SDK |
| EJS | 5.x | 模板引擎 |
| Jest | 30.x | 测试框架 |
| Prettier | 3.x | 代码格式化 |
| Husky | 8.x | Git hooks |
# 开发
npm run dev # fastify-cli 热重载
node app.js # 直接启动
# 测试
npm test # Jest 测试(带覆盖率)
npm run test:watch # Jest 监听模式
# 代码格式化
npm run format # Prettier 格式化所有文件
npm run format:check # 检查代码格式
npm run lint # 运行代码检查本项目使用 Husky + lint-staged + Prettier 自动格式化代码。
提交前会自动执行:
- Prettier 格式化暂存文件
- Jest 运行测试
git add .
git commit -m "feat: 添加新功能" # 提交信息使用简体中文/submit.php路由路径不可修改(易支付协议兼容)constans.js文件名拼写错误但不可修改(autoload 依赖)- 微信支付金额使用
parseInt,不支持小数(如 0.01 元会变成 0 分) - 无 CI/CD、无 Dockerfile、无 linter 配置
- ✅ 原型链污染防护(hasOwnProperty 检查)
- ✅ 时序攻击防护(crypto.timingSafeEqual)
- ✅ XSS 防护(EJS 自动转义)
- ✅ SSRF 防护(URL 安全验证)
- ✅ 订单原子更新(防止重复通知)
- ✅ 优雅关闭处理(SIGTERM/SIGINT)
- ✅ 请求限流(100 请求/分钟)
MIT