next-serverless
· 阅读需 6 分钟
基于 Next.js 15 + TypeScript 构建的 Serverless API 服务,集成 NeonDB(PostgreSQL)、Pusher 实时推送、Vercel Blob 文件存储和飞书通知。
快速开始
npm run dev
# or
pnpm dev
访问 http://localhost:3000 查看首页。
环境变量
DATABASE_URL= # NeonDB PostgreSQL 连接字符串(pooled,推荐用于大多数场景)
DATABASE_URL_UNPOOLED= # NeonDB PostgreSQL 连接字符串(不经 pgbouncer,用于需要直连的场景)
BLOB_READ_WRITE_TOKEN= # Vercel Blob 读写 Token
# Pusher(服务端触发事件;前端只需 key + cluster,见下文「前端接入 Pusher」)
PUSHER_APP_ID= # Pusher App ID
PUSHER_KEY= # 前端订阅用公钥(可暴露到浏览器)
PUSHER_SECRET= # 仅服务端,切勿写入前端
PUSHER_CLUSTER= # 例如 ap3
前端接入 Pusher(与本项目配合)
本仓库在 PUT /api/generic/update 更新成功且表名在服务端白名单内时,会调用 pusher.trigger 推送事件。前端使用与后端同一 Pusher 应用的 key + cluster 即可订阅(不要把 PUSHER_SECRET 放到前端)。
约定(与 lib/pusher.ts 一致)
| 项目 | 说明 |
|---|---|
| Channel 名 | 与数据库表名相同(例如 FuxiKuangBiao) |
| 事件名 | 当前为 updated(仅 update 接口会触发) |
| 白名单 | 仅 ENABLED_TABLES 中的表会推送;默认包含 FuxiKuangBiao。其它表不会收到事件 |
| Payload | { id, tableName, ...本次 PUT 请求体里除 id/tableName 外的更新字段 } |
POST /api/generic/create、DELETE /api/generic/delete 内 Pusher 调用当前为注释状态,创建/删除不会推送。
安装依赖(前端项目)
npm install pusher-js
# 或 pnpm / yarn 等价安装
最小示例(浏览器 / Vue / React 均可)
将 YOUR_PUSHER_KEY、YOUR_CLUSTER 换成与本服务环境变量 PUSHER_KEY、PUSHER_CLUSTER 相同的值(与 lib/pusher.ts 中配置一致)。
import Pusher from 'pusher-js';
const pusher = new Pusher('YOUR_PUSHER_KEY', {
cluster: 'YOUR_CLUSTER',
forceTLS: true,
});
// 与操作的表名一致;仅白名单表在更新时会有事件
const channel = pusher.subscribe('FuxiKuangBiao');
channel.bind('updated', (data: Record<string, unknown>) => {
// data 含 id、tableName 及更新的字段,可据此刷新列表或合并状态
console.log('row updated', data);
});
// 组件卸载时取消订阅,避免泄漏
// channel.unbind_all();
// pusher.unsubscribe('FuxiKuangBiao');
联调注意
- 同一应用:前端
key/cluster必须与部署本 API 时使用的 Pusher 应用一致。 - 公开 Channel:当前为公共 channel(表名字符串)。若改为
private-/presence-前缀,需在服务端配置 Channel authorization,本仓库未内置该接口。 - 扩展更多表:在
lib/pusher.ts的ENABLED_TABLES中加入表名并重新部署后,对该表执行PUT /api/generic/update才会向同名 channel 发updated。
API 接口文档
通用 CRUD 接口 (/api/generic)
这组接口支持对任意数据库表进行增删改查,通过 tableName 参数指定操作的表(默认为 FuxiData)。
POST /api/generic/create — 创建记录
请求体
{
"tableName": "FuxiData",
"field1": "value1",
"field2": "value2"
}
| 字段 |
|---|
