npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rongyan/wxpost-server

v0.1.4

Published

微信公众号内容发布服务,支持多账号,提供图片上传、草稿管理和发布等 HTTP 接口

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-server

IP 白名单

微信接口要求服务器 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" }'