恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
将微信文件传输助手搬进NAS:用公众号实现自动存档
首页
资讯中心
/
将微信文件传输助手搬进NAS:用公众号实现自动存档
将微信文件传输助手搬进NAS:用公众号实现自动存档
发布时间:2026/10/22 5:00:13
1. 项目背景与核心思路拆解1.1 为什么要把文件传输助手搬进 NAS先聊一个很真实的痛点场景。你正坐在通勤车上手机收到一份重要的合同初稿或者一段拍摄现场的视频素材又或者是从同事那里转来的压缩包。这时候你只有两个选择一是打开网盘客户端等它上传完成二是先用微信的文件传输助手把文件塞进去等回到家再打开电脑重新下载。网盘上传速度嘛大家都懂小文件还好遇到大视频或压缩包那个进度条能让你对着屏幕深呼吸好几次。至于传文件助手它确实快但文件堆积在里面没有自动分类过几天想找东西就得翻半天聊天记录而且手机存储空间吃紧时还得定期手动清理。这个方案看起来方便实际上文件等于躺在一个“临时中转站”里没有真正的归宿。所以“把文件传输助手搬进 NAS”这个想法本质上是想把“聊天窗口发文件”这种顺手的使用习惯和 NAS 本地存储的自由度结合起来——你仍然是在微信里发文件但文件落地的位置从聊天服务器变成了自家 NAS 的硬盘。wxchat 这个项目就是做这件事的。1.2 wxchat 解决了什么问题简单说wxchat 搭建了一条从微信到 NAS 的传送链路。发文件的人是你自己接收文件的是 NAS 上一个指定的文件夹整个过程不需要额外安装 App不需要打开 NAS 的管理页面不需要记 IP 或端口更不需要学什么 WebDAV 配置。你只需要在微信里找到这个“联系人”把文件发送过去然后就完了。这里说的“联系人”其实是公众号或个人号的会话入口。wxchat 的本质是一个跑在 NAS 上的服务程序它对接微信的消息接口收到文件后把二进制数据保存到本地磁盘同时给你回一条消息告诉你“已存放到哪个目录、文件大小是多少”。这套交互模式几乎没有任何学习成本家里长辈都能直接用。我自己的实测感受是这种方案最大的优势不是“快”——毕竟文件传输助手也不慢——而是文件掉进了自己的硬盘。NAS 上可以设定目录结构、可以跑后续的备份任务、可以给文件打标签、可以建索引。文件进了 NAS才真正进入了自己的数据管理体系。而用文件传输助手文件永远停留在“待处理”的状态。1.3 适合谁来参考和实施这个项目适合这几类人已经有一台 NAS并且希望有一个更顺手的移动端文件收集方式的人不想安装额外 App、不想折腾客户端配置只想像聊天一样发文件的人对自托管数据比较在意不希望文件长时间留在第三方服务器上的人想借这个项目熟悉微信公众号消息接口、服务器消息接收和文件流处理流程的开发者。技术门槛不算高主要涉及基础的 HTTP 服务、微信公众号消息加解密、文件流处理、目录权限管理这些知识点。如果你已经玩过 Docker、部署过一些 NAS 上的小服务那这套东西对你来说顶多算一个比较完整的练手项目。2. 技术方案选型与架构设计思路2.1 接入方式选型公众号、企业微信还是个人号第一个需要决策的问题是用什么形态的微信账号来收发消息。我这里说的是“对接微信消息接口”但微信生态里的接口分不同门类选型直接决定了开发量和长期稳定性。微信公众号服务号这是最常用的选型。服务号支持服务器配置可以接收用户发来的文字、图片、语音、视频、文件等消息支持被动回复。个人开发者申请一个订阅号或服务号并不难接口文档公开社区资料丰富。wxchat 项目选的就是这个方向。企业微信企业微信也有消息接收接口支持的文件类型更丰富且不需要做 URL 校验时那种繁琐的加解密处理。但企业微信的定位是办公协作你需要注册企业主体或使用某个“企业”身份个人折腾起来有点别扭。个人微信协议市面上有一些基于逆向协议或 Hook 方案做的个人号机器人确实能做到“个人号收发文件”。但这个方向灰色地带很多账号存在封禁风险协议库也需要持续维护。自托管项目如果追求稳定不建议碰这个方向。所以 wxchat 选择“公众号”路线是综合了稳定性、开发门槛、长期维护成本之后的合理选择。公众号的接口权限虽然有一定限制但接收文件消息和回复消息这两块是完整开放的对“文件传输”这个场景来说已经足够。2.2 部署形态Docker 优先NAS 上的服务部署方式大体有 Direct 安装、虚拟机、Docker 三种。wxchat 选择 Docker 容器化部署理由很直接NAS 的类型太多了。群晖的系统、威联通的系统、各种 DIY 黑群晖、甚至树莓派刷的系统系统环境差异很大。如果做的是裸机安装脚本光是每台机器的 Python 版本、依赖冲突、系统服务管理方式都能折腾掉半天。Docker 把运行时环境隔离起来镜像打好之后在任何支持 Docker 的 NAS 上拉起来就能跑。我自己的习惯是在 NAS 上新建一个共享文件夹专门放容器数据比如 docker/wxchat下面再分 config 和 data 两个子目录。config 放程序配置data 放接收到的文件。这样一来程序升级也好、容器重建也好配置文件和数据都不会丢。Docker 镜像的构建也不复杂基础镜像用 python:3.11-slim 就够项目依赖就那几样Flask、requests、pycryptodome。其中 pycryptodome 是用于微信公众号消息加解密的。构建时把依赖装好、把项目代码 COPY 进去、暴露一个 80 端口完事。2.3 内部模块划分wxchat 的服务内部我把它拆成了四个模块分工很清晰消息接收与校验模块负责处理微信服务器发来的 GET 验证请求和 POST 消息推送。这个模块的核心工作是做签名校验和消息体加解密。微信服务器每次推送会带 signature、timestamp、nonce 参数服务端需要用 Token 按规则重新计算签名比对如果启用了加密模式还要用 AES 对消息体做解密和加密。消息类型分发模块拿到解密后的 XML 消息体之后根据 MsgType 字段判断类型。文本消息、图片消息、文件消息走不同的处理分支。wxchat 里最核心的是接收文件消息也就是 MsgType 为 event 且 Event 为 msg_or_media 的情况或者部分类型的媒体文件消息。文件下载与存储模块微信推送的文件消息里通常会带媒体 ID服务端需要调用微信的素材接口拉取文件流然后写入 NAS 的目标目录。这里的目录结构我做了一套按日期归档的方案举例说收到文件先落到当前月份的目录再按文件类型细分。回复消息模块文件处理完之后通过客服接口或被动回复的方式给用户推一条文字消息告知存放路径、文件名、大小方便随时确认传输结果。这种拆分的好处是每个模块可以独立测试。比如我先用假数据测试消息分发逻辑再去联调微信真实接口出了问题很容易定位在哪一层。3. 环境准备与基础配置实操3.1 前置条件清单开始实际操作之前先把该准备的东西列清楚。项目说明NAS 设备支持 Docker 即可群晖、威联通、绿联、极空间、DIY 机器都行公众号建议申请一个订阅号个人主体即可不需要认证也能用到本次需要的接口能力服务器 IPNAS 的公网访问能力或用内网穿透方案把服务端口暴露到公网域名公众号后台配置服务器 URL 需要用到且微信要求 80 端口或 443 端口的 HTTP 服务基本开发环境一台电脑用于写代码、打镜像不要求多高配置注意微信公众号服务器配置需要填写一个公网可访问的 URL。如果你家里的宽带没有公网 IP可以用内网穿透工具比如 frp、tailscale 的 Funnel 功能或者一些云服务商的隧道能力。核心是让微信服务器能够访问到你的 NAS 服务端口。3.2 公众号后台配置步骤公众号这边需要设置的地方有三个服务器配置在公众号后台的“设置与开发” - “基本配置”里找到服务器配置。需要填写 URL、Token、EncodingAESKey。Token 是你自己定义的一串随机字符串EncodingAESKey 可以点随机生成。消息加解密方式选择“安全模式”。IP 白名单在基本配置里设置服务器 IP 白名单。这里填的是你 NAS 的公网出口 IP不填的话接口调用会被拒绝。注意如果你的出口 IP 是动态的这个值需要及时更新。关闭自动回复冲突如果公众号开启了关键词自动回复之类的功能可能会和服务器配置的消息接收产生冲突。实测下来服务器配置开启后微信会把消息推送到服务器但某些基础自动回复还是会生效容易造成用户收到两条回复。建议把不需要的自动回复规则清理干净。配置完成之后提交的时候微信服务器会向你的 URL 发一次 GET 验证请求这个验证通过之后配置才会生效。所以你要先把服务跑起来再去点击提交。验证逻辑就是那段经典的签名校验把 token、timestamp、nonce 排序后拼接做 SHA-1 哈希和签名比对。3.3 目录结构设计与存储规划在 NAS 上我给 wxchat 规划了这样的目录结构/docker/wxchat ├── config/ │ └── config.yaml └── data/ ├── 2025-01/ │ ├── image/ │ ├── video/ │ ├── document/ │ └── other/ ├── 2025-02/ └── ...config.yaml 里存放公众号配置、存储路径、允许接入的微信用户 OpenID 列表。data 目录按“年-月”归档再按文件类型分子目录。这个命名方式让文件系统的可读性很强用户从微信发来一张照片落到磁盘上就是 data/2025-06/image/photot.jpg一眼能看出时间、类型和文件名。存储盘建议用 NAS 上容量较大、做好冗余的那个卷。如果文件量很大可以把 data 目录单独挂载到大容量硬盘上不要让容器内部的 data 和系统盘混在一起。我在 docker-compose 里直接用 volume 映射volumes: - ./config:/app/config - /volume1/data/wxchat:/app/data把宿主机的数据目录映射到容器内 /app/data这样容器随便重建文件都安全地留在 NAS 上。4. 核心功能实现与代码解析4.1 消息验证接口微信服务器的握手微信服务器配置提交的时候会往你的 URL 发一个 GET 请求带着 signature、timestamp、nonce、echostr 四个参数。你的服务需要做的是把 token、timestamp、nonce 三个字符串先按字典序排序然后拼接成一个字符串做 SHA-1 哈希再把哈希结果和 signature 对比。一致的话原样返回 echostr 给微信服务器验证就通过了。用伪代码表达就是def verify_signature(token, timestamp, nonce, signature): items sorted([token, timestamp, nonce]) raw .join(items).encode(utf-8) hashed hashlib.sha1(raw).hexdigest() return hmac.compare_digest(hashed, signature)这段逻辑没什么难度但有个小坑token 在公众号后台和本地配置必须完全一致差一个字符验证就失败。而且微信的验证请求很严格返回的 echostr 必须是原样不能加了空格或换行。4.2 消息接收与加解密配置了安全模式之后微信推送过来的 POST 消息体是加密的。请求体长这样xml ToUserName![CDATA[gh_xxx]]/ToUserName Encrypt![CDATA[加密串]]/Encrypt /xml而你的服务响应给微信的消息也需要加密。加解密的算法是 AES-256-CBC密钥由 EncodingAESKey 生成。微信提供了一个加解密示例代码库官方支持多种语言。实际开发时用好这个基础库重点做好两个处理一是解密后的 XML 需要做消息类型解析二是生成回复消息时要做正确填充。加密这一块是最容易出问题的环节但也是文档最全的部分。我踩过的一个坑是编码问题。微信的 AES 加解密里密钥字符串需要做一次 Base64 Decode 之后才是真正的 32 字节密钥而签名用的 Token 是明文字符串。如果把两者搞混解密出来的内容就是乱码或者直接报错。4.3 文件消息的接收链路微信里支持接收文件的时机分两类一类是用户直接在聊天窗口发送文件这类消息推给你的是 URL 类型的消息另一类是订阅号/服务号的消息中夹带的媒体素材。wxchat 目前处理的是用户直接发文件时推送的事件。微信的文档里这类消息一般表现为 MsgType 为 event、Event 为 msg_or_media 的消息体里面有一条 MediaId。拿到 MediaId 之后调用微信的素材下载接口def download_media(media_id, access_token): url fhttps://api.weixin.qq.com/cgi-bin/media/get?access_token{access_token}media_id{media_id} resp requests.get(url, streamTrue) return resp.content这里要注意素材下载接口针对临时素材文件大小限制在较宽松的范围但视频类素材微信在传输过程中可能重新编码下载下来的文件格式未必和原始文件完全一致。实测过程中发现微信对视频文件会做转码处理比如某些格式的 MP4 下载后可能变成另一个编码规格这个属于微信侧的行为目前无法完全控制和规避。作者需要在文档里明确说明。access_token 的获取倒是标准流程拿 AppID 和 AppSecret 去微信接口换 token。需要注意的是 access_token 两小时有效期而且获取接口有频次限制。所以项目里我做了 token 缓存别每次下载文件都去换一次。4.4 文件落盘与目标目录匹配文件下载到内存之后要做的事情是确定存放路径。这块看似简单但做过文件处理的人都懂文件名和扩展名的坑是最多的。我拆了几步第一步判断文件类型。根据文件名的后缀或者更稳妥地用 Python 的 mimetypes 模块去判断 MIME 类型决定进 image、video、document 还是 other 目录。微信发过来的文件名有些是带表情符号或特殊字符的落地前必须做清洗否则某些文件系统直接报 illegal filename 错误。第二步重名处理。同一秒同文件名的情况虽然少但真的有。我的策略是在文件名后加时间戳比如 report_20250601-143022.pdf。用 uuid 也行但 uuid 可读性太差用户看到一堆十六进制串找不到哪个文件是自己刚才发的。时间戳加原文件名既能保持辨识度又基本不会重名。第三步目录创建。日期目录和类型子目录如果不存在就自动创建。Python 的 os.makedirs 加上 exist_okTrue 参数一行代码解决。第四步写入反馈。文件写完之后把完整路径、文件大小、类型信息拼成一条文字消息调用客服接口推给用户。回复消息里我会提醒一下“文件已存入 NAS 2025年6月目录”方便用户心里有数。4.5 用户权限控制这是个容易被忽略的功能点。公众号算是一个公开入口如果服务没有任何访问控制理论上任何知道这个公众号的人都能往你 NAS 里塞文件。wxchat 的做法是在 config 里维护一份允许访问的 OpenID 列表。当用户发来消息时先从解密后的 XML 里取出 FromUserName这是微信用户的 OpenID然后和配置的列表做匹配。不在列表里的用户回复一条“抱歉你没有访问权限”不执行文件下载和存储逻辑。有朋友可能觉得多此一举毕竟公众号是私有的。但实际操作中公众号是可以被搜索和关注的而且如果有人恶意发大文件你的存储盘很快就满了。权限控制这个护栏必须有而且建议配置好默认拒绝策略。5. 完整流程实操演示与参数说明5.1 从微信发文件到 NAS 的目标效果先说一个完整的实操链路方便你验证自己搭的服务是否正常手机微信打开 wxchat 对应的公众号聊天窗口点击加号选择文件发送一个 PDF 文档几秒后微信收到一条回复“收到文件技术方案v2.pdf大小 2.3MB已存入 /volume1/data/wxchat/2025-06/document/”打开 NAS 的文件管理器进入对应路径文件确实在那里。这套流程走完项目的基础就算跑通了。5.2 用 docker-compose 搭建运行环境我的 docker-compose 配置长这样比较精简但很实用version: 3 services: wxchat: image: wxchat:latest container_name: wxchat restart: unless-stopped ports: - 8090:80 volumes: - ./config:/app/config - /volume1/data/wxchat:/app/data environment: - TZAsia/Shanghai端口映射我选的是宿主机 8090 映射容器 80没有直接用 80 端口因为 NAS 上 80 端口经常被其他服务占用。容器内部暴露 80宿主机用 8090Nginx 反代或内网穿透做端口转发时也更灵活。启动命令很简单docker-compose up -d日志查看docker logs -f wxchat看到类似server started on 0.0.0.0:80的输出说明服务已经起来了。5.3 第一次配置的完整过程演示实际实施的时候建议按照这个顺序操作避免来回折腾第一步把代码构建成镜像或直接拉取已发布的镜像。本地构建docker build -t wxchat:latest .第二步编辑 config.yaml填入公众号后台的 AppID、AppSecret、Token、EncodingAESKey以及允许的 OpenID 列表。第三步启动容器确认日志无报错。第四步配置内网穿透或公网入口把 NAS 的 8090 端口暴露成一个公网 URL。我用的是 frp 的 tcptunnel 模式或者如果你用的是 Tailscale Funnel直接把 HTTPS 流量转进来也行。第五步在公众号后台填写 URL。URL 格式类似https://你的域名/wxToken 填 config 里的 TokenEncodingAESKey 填 config 里的那个。然后提交。第六步微信服务器会发送验证请求如果签名校验通过页面会提示配置成功。第七步自己先在微信上发一条文本消息测试再发一个文件测试。日志里会打印消息类型和处理结果。5.4 关键参数配置参考表参数名示例值说明AppIDwxa1b2c3d4e5f6公众号的唯一标识AppSecret32位十六进制串调用接口用的密钥注意保密Tokenwxchat2025token自己定义与后台保持一致EncodingAESKey43位字符串后台随机生成配置里填入同一串AllowedUsers[oAbCdEfGhI...]有权限访问的 OpenID 列表StorageRoot/app/data容器内文件存储根路径注意 AppSecret 不要提交到 Git 仓库。我吃过这个亏有一次把配置模板带上默认密钥推到仓库几小时后就发现公众号的接口被人调去发了垃圾消息。现在 config 文件里的敏感项一律用环境变量注入模板文件只留占位符。6. 常见问题与排查技巧实录6.1 验证请求一直失败微信提示“URL 未通过验证”这个问题是最常见的排查顺序推荐如下确认你的 URL 确实可以从公网访问。直接在浏览器打开https://你的域名/wx看是否有响应。确认服务返回的是纯文本 echostr没有多余的空格或换行。确认 Token 在本地配置和公众号后台配置中完全一致。看容器日志。如果日志里根本没出现收到请求的记录说明请求根本没到你的服务问题出在公网入口或端口转发上。还有一个容易被忽略的情况微信验证请求的方法只能是 GET如果你在服务入口做了强制 HTTPS 跳转或加了 Basic Auth微信的请求就被挡住了。验证期间先别做这些限制。6.2 消息能收到但文件下载失败能收到消息说明验证和消息接收链路没问题文件下载失败主要看两个环节一是 access_token 是否有效。如果 token 过期或 AppSecret 错误微信接口返回的是 40001 之类的错误码。处理方式是检查 token 缓存逻辑token 过期要自动刷新。二是媒体 ID 的有效期问题。微信的临时素材有效期一般是 3 天用户发文件后你得尽快下载。如果消息队列拥堵或服务长时间停止媒体 ID 可能已经失效。这种情况只能让用户重发。6.3 文件落盘了但目录结构不对如果你发现所有文件都跑到了 other 目录大概率是文件类型判断的逻辑太严格了。微信传过来的文件名有时不携带标准扩展名比如压缩包解压后的某些文件、没有后缀名的脚本文件。我的建议是改用“双保险”策略先看后缀后缀无法判断时看 MIME 类型再不行就归入 other。分类不必追求百分之百准确但至少别把 PDF 和图片丢一起。6.4 用户权限校验失败消息被当成了“无权限用户”这个坑我踩过一次。微信推送消息里的 FromUserName 是用户的 OpenID而 OpenID 是公众号维度的同一个微信用户在不同的公众号下 OpenID 不同。你测试时用手机关注公众号发的第一条消息里的 FromUserName才是这个用户的真实 OpenID。别用网页后台看到的用户标识去填配置。6.5 接收大文件超时微信公众号对媒体素材的下载接口没有特别严苛的超时限制但你的服务在下载大文件时如果长时间不发响应可能会导致微信超时重试或连接断开。我在代码里做了异步处理收到消息后先回复“开始接收”再后台下载文件下载完成后推送结果。这样用户端的体验更好也避开了接口同步等待的限制。6.6 重复收到同一文件的问题微信的服务器推送机制是做了重试的如果你的服务处理消息时异常退出微信会尝试重新推送同一条消息。如果没有做幂等控制就会出现“收到一个文件存了两份”的情况。我的解决办法是引入一个简单的消息去重表记录已处理消息的 MsgId。每次收到消息先在本地 SQLite 里查一下 MsgId 是否已存在存在就丢弃不存在再处理。SQLite 在 NAS 这种资源环境下性能完全够用不必为了这个小项目再上 Redis。7. 进阶扩展与日常维护心得7.1 多用户支持与家庭共享如果想把 wxchat 的能力分享给家人用不要只是把所有人的 OpenID 塞进同一个列表——那样所有文件都堆在一个目录里找东西会很痛苦。建议在配置里增加每个用户和一个命名空间子目录的对应关系。比如张三 - /data/zhangsan/ 李四 - /data/lisi/这样一家人各自往自己的目录里丢文件互不干扰协作也清晰。权限列表和目录映射放在同一个配置节里解析逻辑稍微改一下即可。7.2 与 NAS 既有任务的联动文件进了 NAS才只是开始。我在 wxchat 收到的文件目录上加了几个自动化任务每周日凌晨对 data 目录做一次增量备份到外接硬盘防止磁盘故障丢数据对图片子目录跑一个质量管理脚本压缩体积过大的图片保留原图 90% 以上质量的同时减小占用对 document 子目录建立索引每天生成一个清单文件放到共享盘里方便搜索。这些联动任务可以用 NAS 自带的计划任务功能做也可以在你的 Docker 里再挂一个 cron 定时器按你熟悉的方式来做。7.3 安全加固措施在公众号后台配置里有“开发环境”和“生产环境”之分。生产环境务必开启安全模式并且定期更换 EncodingAESKey。另外不要将公众号 AppSecret 写在任何能被前端页面读取的地方。在内网穿透层面建议只在需要调试时开启公网映射日常使用如果处于同一局域网直接用局域网地址访问即可。如果确实需要长期公网使用优先选 HTTPS 方案并确认你的穿透工具支持自动签发证书。7.4 维护过程中的一个体会这个项目做了大概两周之后我发现最费时间的并不是编码而是“匹配微信的规范”。微信的加解密流程、消息重试机制、素材接口的行为边界每一块都需要看文档和实际测试结合着来理解。代码本身并不复杂核心服务加上配置文件总共也就几百行。所以如果你照着文档搭完发现哪里效果和预期不符不用急着怀疑自己的代码水平先用日志确认微信服务器到底发了什么内容过来、你的服务又响应了什么回去。把这两个信息对齐问题通常就清楚了一大半。做这类对接类项目养成一个习惯每次改动代码之前先把当前的行为记录下来改完之后对照日志对比。微信侧的接口行为会偶发调整日志是最好的排障依据。7.5 如果你还想继续扩展wxchat 目前做的是“收”下一步可以考虑做“发”。比如通过给公众号发一条带特定指令的文本消息让 NAS 自动把指定目录下的最新文件推送到你微信上。这个需要用到微信公众号的主动推送能力逻辑上是用客服消息接口下发文件对素材的获取方式有些不同但整体链路你已经熟悉了。另外还可以把文件处理能力从“存下来”升级到“归档分类”接入 NAS 上的多媒体管理工具自动生成视频缩略图、提取 PDF 文本内容做全文检索。这样文件传输助手就真的变成一个智能收件箱了。从个人角度说wxchat 这类项目的价值不在于功能本身多花哨而在于你把日常繁琐的文件中转流程变成了一个可掌控的、数据留在自己手里的闭环。这种感觉和用在线网盘完全不同——深夜收到一个文件看着它安安静静落进家里硬盘的那一刻你会觉得这套折腾是值得的。