@rongyan/wxpost-server
v0.1.4
Published
微信公众号内容发布服务,支持多账号,提供图片上传、草稿管理和发布等 HTTP 接口
Maintainers
Readme
@rongyan/wxpost-server
微信公众号内容发布服务,支持多账号,提供图片上传、草稿管理和发布等 HTTP 接口。
要求
- Node.js >= 18
- 微信公众号开发者账号(AppID + AppSecret)
- 服务器 IP 已加入微信公众平台 IP 白名单
安装
npm install -g @rongyan/wxpost-server@latest初始化配置
首次运行以下命令,程序会自动在 ~/.@rongyan/env.json 创建配置模板:
wxpost-server --help
配置文件已创建:/root/.@rongyan/env.json
请编辑该文件,填入你的公众号 AppID 和 AppSecret,然后重新启动。
格式说明:
port — 监听端口(也可用 --port 参数或 PORT 环境变量覆盖)
api_key — HTTP 接口鉴权密钥
upload_dir — 本地图片存储目录(默认 ~/.@rongyan/upload_dir/)
log_dir — 日志目录(默认 ~/.@rongyan/log/)
defaultAccount — 默认使用的 AppID
accounts — 以 AppID 为 key,每个账号填写对应的 appSecret编辑 ~/.@rongyan/env.json,填入真实值:
{
"port": 3000,
"api_key": "your-api-key",
"upload_dir": "/Users/yourname/.@rongyan/upload_dir",
"defaultAccount": "wx_appid",
"accounts": {
"wx_appid": {
"appSecret": "your-app-secret"
},
"wx_another_appid": {
"appSecret": "another-app-secret"
}
}
}| 字段 | 说明 |
|------|------|
| port | 配置文件中的默认监听端口,默认 3000;可被 --port 参数或 PORT 环境变量覆盖 |
| api_key | HTTP 接口鉴权密钥 |
| upload_dir | 图片上传临时目录,默认 ~/.@rongyan/upload_dir/ |
| defaultAccount | 不传 appid 参数时使用的默认账号(填 AppID) |
| accounts | 多账号配置,以 AppID 为 key,每个账号填写 appSecret |
启动
# 直接启动
wxpost-server
# 指定端口
wxpost-server --port 8080
# 通过环境变量指定端口
PORT=8080 wxpost-server端口优先级:--port 参数 > PORT 环境变量 > 配置文件 port > 默认 3000
使用 PM2(推荐生产环境)
pm2 start wxpost-server --name wxpost-server -- --port 3000
pm2 save # 保存进程列表,重启后自动恢复
pm2 startup # 设置开机自启(按提示执行输出的命令)
pm2 logs wxpost-server # 查看日志
pm2 restart wxpost-server
pm2 stop wxpost-serverIP 白名单
微信接口要求服务器 IP 在白名单内。配置路径:
微信公众平台 → 设置与开发 → 基本配置 → IP 白名单
token 缓存
access_token 自动缓存至 ~/.@rongyan/tokens.json,有效期 7200 秒,提前 5 分钟自动刷新,多进程共享同一缓存文件。
API
所有接口均需鉴权,支持以下两种方式(二选一):
Authorization: Bearer <api_key>
X-Api-Key: <api_key>所有请求和响应均为 JSON(上传图片除外)。响应体统一包含 ok 字段,true 表示成功,false 表示失败(同时包含 error 字段)。
多账号场景可通过 ?appid= 查询参数指定账号,不传则使用 defaultAccount。
POST /upload-image
上传图片到微信服务器,返回微信 CDN 图片地址。
请求格式: multipart/form-data
| 字段 | 类型 | 说明 |
|------|------|------|
| media | file | 图片文件,仅支持 JPG/PNG(按文件内容识别),大小须严格小于 1MB |
查询参数:
| 参数 | 说明 |
|------|------|
| appid | 可选,指定使用的公众号 AppID,不传使用默认账号 |
请求示例:
curl -X POST http://localhost:3000/upload-image \
-H "Authorization: Bearer your-api-key" \
-F "media=@/path/to/image.jpg"成功响应:
{
"ok": true,
"url": "https://mmbiz.qpic.cn/..."
}错误响应:
| 状态码 | 说明 | |--------|------| | 401 | 鉴权失败 | | 400 | 格式不支持(非 JPG/PNG) | | 413 | 图片超过 1MB,请压缩后重试 | | 502 | 微信接口调用失败 |
POST /upload-material
上传图片为永久素材,返回 media_id 和微信 CDN 地址。永久素材可用于草稿封面图(thumb_media_id)等需要持久化的场景。
请求格式: multipart/form-data
| 字段 | 类型 | 说明 |
|------|------|------|
| media | file | 图片文件,支持 JPG/PNG/GIF/BMP(按文件内容识别),大小须严格小于 10MB |
查询参数:
| 参数 | 说明 |
|------|------|
| appid | 可选,指定使用的公众号 AppID,不传使用默认账号 |
请求示例:
curl -X POST http://localhost:3000/upload-material \
-H "Authorization: Bearer your-api-key" \
-F "media=@/path/to/cover.jpg"成功响应:
{
"ok": true,
"media_id": "xxx",
"url": "https://mmbiz.qpic.cn/..."
}
url仅在微信/腾讯域名下有效,不可在外部网页直接引用。
错误响应:
| 状态码 | 说明 | |--------|------| | 401 | 鉴权失败 | | 400 | 格式不支持(非 JPG/PNG/GIF/BMP) | | 413 | 图片超过 10MB,请压缩后重试 | | 502 | 微信接口调用失败 |
POST /draft/add
新增草稿,返回草稿的 media_id。
请求格式: application/json
请求体:
{
"articles": [
{
"article_type": "news",
"title": "文章标题",
"author": "作者",
"digest": "摘要",
"content": "<p>正文 HTML</p>",
"content_source_url": "https://example.com",
"thumb_media_id": "封面图素材ID",
"need_open_comment": 0,
"only_fans_can_comment": 0,
"pic_crop_235_1": "0,0,1,0.4985",
"pic_crop_1_1": "0,0,1,1",
"cover_info": {},
"product_info": {}
}
]
}articles 字段说明:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| article_type | string | 否 | "news"(图文,默认)或 "newspic"(图片) |
| title | string | 是 | 超过 64 字自动截断 |
| author | string | 否 | 最多 16 字 |
| digest | string | 否 | 摘要,最多 128 字;不填则从正文自动截取 |
| content | string | 是 | 正文 HTML |
| content_source_url | string | 否 | 点击"阅读原文"跳转的 URL |
| thumb_media_id | string | news 类型必填 | 封面图的永久素材 MediaID |
| image_info | object | newspic 类型必填 | 图片列表,{ "list": [...] },最多 20 张 |
| need_open_comment | number | 否 | 是否开启评论:0 关闭,1 开启 |
| only_fans_can_comment | number | 否 | 仅粉丝可评论:0 所有人,1 仅粉丝 |
| pic_crop_235_1 | string | 否 | 封面裁剪坐标(2.35:1) |
| pic_crop_1_1 | string | 否 | 封面裁剪坐标(1:1) |
| cover_info | object | 否 | 封面裁剪信息对象 |
| product_info | object | 否 | 商品信息对象 |
成功响应:
{
"ok": true,
"media_id": "草稿的media_id"
}错误响应:
| 状态码 | 说明 | |--------|------| | 401 | 鉴权失败 | | 400 | 参数校验失败或微信接口返回错误 | | 413 | 请求体超过 2MB | | 502 | 获取 access_token 失败 |
POST /draft/list
获取草稿列表(分页)。
请求格式: application/json(请求体可省略,使用默认值)
请求体:
{
"offset": 0,
"count": 20,
"no_content": 0
}| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| offset | number | 0 | 起始偏移,从 0 开始 |
| count | number | 20 | 返回数量,1–20 |
| no_content | number | 0 | 1 表示不返回正文内容,0 返回 |
成功响应:
{
"ok": true,
"total_count": 100,
"item_count": 20,
"item": [
{
"media_id": "草稿ID",
"update_time": 1234567890,
"content": {
"news_item": [
{
"title": "文章标题",
"author": "作者",
"digest": "摘要",
"content": "<p>正文</p>",
"thumb_media_id": "封面素材ID",
"url": "草稿预览链接",
"article_type": "news"
}
]
}
}
]
}错误响应:
| 状态码 | 说明 | |--------|------| | 401 | 鉴权失败 | | 400 | 参数错误或微信接口返回错误 | | 502 | 获取 access_token 失败 |
POST /draft/publish
发布草稿为正式图文,返回发布任务 ID。
请求格式: application/json
请求体:
{
"media_id": "草稿的media_id"
}| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| media_id | string | 是 | 要发布的草稿 ID |
成功响应:
{
"ok": true,
"publish_id": "发布任务ID",
"msg_data_id": "消息数据ID"
}错误响应:
| 状态码 | 说明 |
|--------|------|
| 401 | 鉴权失败 |
| 400 | 缺少 media_id、草稿未通过检查或其他微信错误(含错误码) |
| 502 | 获取 access_token 失败 |
微信错误码:
| 错误码 | 说明 | |--------|------| | 48001 | 接口未授权,确认公众号已开通该能力 | | 53503 | 草稿未通过发布检查,检查草稿内容 | | 53504 | 需前往公众平台官网操作 | | 53505 | 请手动保存成功后再发布 |
典型工作流
# 1. 上传文章封面图,获取永久素材 media_id
curl -X POST http://localhost:3000/upload-material \
-H "Authorization: Bearer your-api-key" \
-F "[email protected]"
# 2. 新增草稿
curl -X POST http://localhost:3000/draft/add \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{
"articles": [{
"title": "文章标题",
"content": "<p>正文内容</p>",
"thumb_media_id": "上一步返回的media_id"
}]
}'
# 3. 发布草稿
curl -X POST http://localhost:3000/draft/publish \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{ "media_id": "上一步返回的media_id" }'