
1. 项目概述与背景最近在折腾博客发布流程的自动化作为一个技术博主我发现自己花在排版、复制粘贴和手动发布上的时间越来越多了。每次写完一篇技术文章都要在本地编辑器、图床、博客后台之间来回切换这个过程不仅繁琐还容易出错。于是我开始寻找一个能让我“一次编写多处发布”的工具最好还能集成到我的写作工作流里。经过一番筛选我把目光投向了 Hermes。你可能听说过 Hermes它最近在开发者社区里挺火的。简单来说Hermes 是一个开源的、支持多平台的博客发布工具。它最吸引我的地方在于它支持通过 MetaWeblog API 来发布内容。这意味着只要你的博客平台比如博客园、WordPress、Typecho 等支持这个古老的但广泛兼容的 API你就能用 Hermes 来管理发布。这听起来就像是为我这种“懒人”量身定做的。我的主力博客就在博客园它恰好也支持 MetaWeblog API。所以我的目标很明确把 Hermes 配置好让它能顺畅地接管我向博客园发布文章的工作。这个过程的挑战在于虽然 Hermes 的文档看起来不错但实际配置过程中特别是和博客园这种国内平台对接时总会遇到一些文档里没写的“坑”。网络环境、API 端点、身份验证方式任何一个细节出问题都可能导致发布失败。我决定把这次从零开始配置、调试到最终成功发布的完整过程记录下来尤其是那些耗费了我大量时间去排查的“坑”和最终的解决方案。如果你也受够了手动发布或者正在寻找一个更优雅的博客发布方案那么这篇记录或许能帮你省下不少时间。2. 核心工具选型与环境准备2.1 为什么选择 Hermes在决定使用 Hermes 之前我也考察过其他方案比如基于 Python 的xmlrpc库自己写脚本或者使用一些更重量级的静态站点生成器如 Hugo 自定义部署脚本。但最终选择 Hermes主要是基于以下几点考虑专注发布功能纯粹Hermes 的核心功能就是发布博客。它不处理静态站点生成不管理主题只做一件事——把本地写好的文章通常是 Markdown 格式通过 API 推送到远程博客平台。这种单一职责的设计让我觉得它更可靠也更容易理解和调试。多平台支持通过 MetaWeblog API 这一通用协议Hermes 理论上可以支持所有实现了该协议的博客系统。这给了我很大的灵活性未来如果我想把文章同步到其他平台比如自建的 WordPress迁移成本会很低。配置驱动易于集成Hermes 使用一个配置文件通常是config.yaml或config.json来管理所有发布设置。这意味着我可以把配置文件和我的文章源码一起用 Git 管理实现发布流程的版本化和可重复性。它也方便集成到 CI/CD 流水线中实现“提交即发布”。活跃的社区与清晰的文档虽然 Hermes 是一个相对较新的项目但其 GitHub 仓库的 Issue 和讨论区比较活跃。官方文档结构清晰对于基本功能的描述是到位的。这为解决问题提供了基础。当然没有完美的工具。Hermes 的“坑”往往在于其与特定平台的深度集成细节以及在某些网络环境下的表现。这也是我写这篇记录的重要原因——把那些“细节”补全。2.2 基础环境搭建我的操作环境是 macOS但步骤在 Linux 和 Windows使用 WSL 或 Git Bash上大同小异。核心是准备好 Node.js 环境因为 Hermes 是基于 Node.js 开发的。第一步安装 Node.js 和 npmHermes 通常作为一个全局命令行工具来安装这依赖于 Node.js 的包管理器 npm。我推荐使用nvmNode Version Manager来管理 Node.js 版本这样可以避免全局安装带来的权限问题也方便切换版本。# 安装 nvm具体命令请参考 nvm 官方 GitHub 仓库的最新说明 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash # 安装完成后重新打开终端或运行 source ~/.bashrc # 或 ~/.zshrc, ~/.profile取决于你的 shell # 安装一个长期支持版本LTS的 Node.js nvm install --lts nvm use --lts # 验证安装 node --version npm --version注意如果你在 Windows 上可以使用nvm-windows项目。确保安装后在终端中能正确执行node和npm命令。第二步安装 Hermes有了 Node.js 环境安装 Hermes 就非常简单了。通过 npm 进行全局安装npm install -g hermes-blogger这里有一个关键点Hermes 在 npm 上的包名可能是hermes-blogger或其他变体而不是简单的hermes。一定要通过官方文档或 GitHub 仓库确认正确的包名。安装完成后你可以通过hermes --version或hermes --help来验证安装是否成功并查看可用命令。第三步准备博客园账户信息在配置 Hermes 之前你需要从博客园后台获取几个关键信息MetaWeblog API 地址对于博客园通常是https://rpc.cnblogs.com/metaweblog/[你的博客用户名]。例如如果你的博客地址是https://www.cnblogs.com/yourname那么 API 地址就是https://rpc.cnblogs.com/metaweblog/yourname。用户名你的博客园登录用户名。密码你的博客园登录密码。请注意出于安全考虑强烈建议使用博客园提供的“管理密码”或“应用程序专用密码”如果支持而不是你的主账户密码。博客园在后台的“设置”-“基本设置”中有一个“MetaWeblog API 访问地址”选项旁边会显示你的用户名。关于密码你需要进入“设置”-“安全设置”找到“MetaWeblog 客户端密码”或类似选项专门为 API 访问生成一个密码。博客ID这个有时需要有时不需要。对于博客园通常用户名就足够了。但如果 API 要求你可以在博客园后台的某个设置页面找到或者尝试留空。把这些信息记在一个临时的地方我们接下来会用到。3. Hermes 配置文件深度解析Hermes 的核心就是这个配置文件。它定义了从哪里获取文章、发布到哪里、以及如何发布。我在这里踩了第一个大坑配置文件的格式和字段含义。3.1 配置文件结构与字段详解Hermes 的配置文件默认名是hermes.config.json通常放在你的博客文章根目录下。一个最基础的、针对博客园的配置骨架如下{ site: { url: https://rpc.cnblogs.com/metaweblog/your_username, username: your_cnblogs_username, password: your_metaweblog_app_specific_password }, posts: { path: ./_posts, draft: false }, publish: { strategy: new, updateExisting: true } }让我们逐一拆解每个部分site对象定义了目标博客站点的信息。url这就是上面提到的 MetaWeblog API 端点地址。这是最容易出错的地方之一。你必须确保这个 URL 完全正确并且是可访问的。博客园的 API 地址格式是固定的。username你的博客园登录名。password重中之重。这里必须填写你在博客园后台为 MetaWeblog API 专门生成的“客户端密码”而不是你的登录密码。如果填错会一直收到认证失败的错误。posts对象定义了本地文章源。path指向存放 Markdown 文章的文件夹路径。例如./_posts表示当前目录下的_posts文件夹。Hermes 会递归扫描这个文件夹下的所有.md文件。draft一个布尔值表示默认情况下发布的文章是草稿状态还是直接公开。false表示直接发布为公开文章。如果你希望先发布为草稿在博客园后台再手动审核发布可以设为true。publish对象定义了发布策略。strategy发布策略。new表示只发布全新的文章根据标题判断是否已存在。all会发布或更新所有文章。初次使用时建议用new测试。updateExisting当strategy为all或检测到文章已存在时是否更新现有文章。设为true可以让你在本地修改文章后重新发布以更新线上版本。3.2 高级配置与 Front Matter 映射基础的配置只能实现最简单的发布。但一篇博客文章通常包含标题、分类、标签、发布时间等元数据。在 Markdown 文件中我们通常使用 Front Matter文件头部的 YAML 或 JSON 块来存储这些信息。Hermes 需要知道如何将这些元数据映射到博客园对应的字段。这就需要更详细的配置。一个增强版的配置可能如下{ site: { ... }, // 同上 posts: { path: ./_posts, draft: false, frontmatter: { title: title, date: date, categories: [categories], tags: tags }, transformers: [ { name: markdown, options: { gfm: true, breaks: true } } ] }, publish: { strategy: new, updateExisting: true, concurrency: 1 } }frontmatter对象这是映射规则的核心。它告诉 Hermes“在我的 Markdown 文件头里title这个字段对应博客文章的标题date对应发布日期categories对应分类注意博客园可能只支持一个分类所以这里用数组的第一个元素tags对应标签。” 如果你的 Front Matter 字段名不同比如用category而不是categories你需要在这里修改映射关系。transformers数组定义了内容处理管道。markdown转换器会将你的 Markdown 文本转换为 HTML因为 MetaWeblog API 通常接收 HTML 格式的内容。options可以指定 Markdown 解析的选项比如gfm: true支持 GitHub Flavored Markdown 的语法如表格、任务列表。concurrency发布时的并发数。设为1是最稳妥的避免因网络或 API 限制导致意外错误。如果你的文章很多且平台稳定可以适当调高以加快速度。实操心得Front Matter 的映射配置需要和你自己的写作习惯完全匹配。建议你先用一篇文章测试使用hermes publish --dry-run如果支持或hermes publish --verbose命令查看 Hermes 解析出的元数据是否正确再实际发布。4. 从本地 Markdown 到博客园发布的完整流程配置好了我们来走一遍完整的发布流程。假设我有一篇名为2023-10-27-hello-hermes.md的文章在./_posts目录下。4.1 文章结构与 Front Matter 规范我的 Markdown 文件内容如下--- title: Hello Hermes: 我的博客自动化发布之旅 date: 2023-10-27T14:30:0008:00 categories: [技术实践] tags: [Hermes, 博客园, 自动化, MetaWeblog] --- ## 引言 长期以来手动发布博客文章一直是一个低效且容易出错的过程... !--more-- ## 正文内容 ...关键点解析Front Matter 格式我使用了三个连续的短横线---包裹 YAML 格式的元数据。这是 Jekyll、Hugo 等静态站点生成器的通用格式也被 Hermes 良好支持。字段对应title,date,categories,tags这些字段名必须与配置文件中的frontmatter映射规则一致。!--more--摘要分割线这是一个非常重要的标记。博客园的文章列表页面会显示文章摘要。Hermes 在发布时会将!--more--之前的内容作为摘要description提交给 API。如果没有这个标记默认会截取文章前一部分字符可能导致格式错乱。强烈建议在你的每篇文章中显式地使用!--more--来定义摘要。日期格式使用 ISO 8601 格式YYYY-MM-DDTHH:mm:ssZ可以避免时区解析错误。08:00表示东八区。4.2 执行发布命令与过程解读在终端中进入配置文件所在的目录通常是博客文章根目录运行发布命令hermes publish如果一切配置正确你会看到类似下面的输出开始扫描文章目录./_posts 找到 1 篇文章。 正在处理Hello Hermes: 我的博客自动化发布之旅 正在发布文章到https://rpc.cnblogs.com/metaweblog/your_username 发布成功文章ID1234567 文章链接https://www.cnblogs.com/yourname/p/1234567.html这个过程背后Hermes 做了以下几件事扫描与解析读取./_posts目录下的所有.md文件解析 Front Matter 和正文内容。内容转换通过配置的transformers这里是 Markdown 转换器将正文转换为 HTML。同时根据frontmatter映射规则提取出标题、分类、标签等元数据。API 交互构造一个符合 MetaWeblog APInewPost或editPost方法的 XML-RPC 请求体。这个请求体包含了title标题、description摘要、categories分类、dateCreated创建日期等字段。特别注意博客园的 MetaWeblog API 实现中文章正文是放在description字段里而摘要可能由博客园自己根据!--more--生成也可能通过其他字段传递。Hermes 的适配器需要处理好这个映射。向配置的url发送 HTTP POST 请求携带你的用户名和密码进行认证。结果处理如果成功API 会返回新创建文章的 ID。Hermes 将这个 ID 和可能的文章链接输出到控制台。如果失败则会抛出错误信息。4.3 发布后的验证与检查发布成功后不要完全依赖命令行输出。立刻打开你的博客园主页和管理后台进行验证主页检查刷新你的博客首页看新文章是否出现在列表里。检查标题、摘要显示是否正常。后台检查登录博客园管理后台进入“我的博客”-“文章管理”。找到刚发布的文章点击“编辑”。检查分类和标签确认分类和标签是否正确设置。有时 API 对分类的支持可能有限可能需要手动调整。检查正文格式查看 HTML 编辑器下的正文内容确认 Markdown 转换后的 HTML 格式是否正确图片链接是否正常如果你在 Markdown 中使用了绝对路径的图床链接这里应该没问题如果是相对路径则需要额外处理。检查摘要确认摘要部分是否是你预期的!--more--之前的内容。重要提示首次使用或更换配置后强烈建议先用一篇测试文章可以设置draft: true发布为草稿进行全流程测试。验证无误后再正式发布你的重要文章。5. 疑难杂症排查与解决方案实录配置和发布过程很少一帆风顺。下面是我在对接博客园时遇到的一些典型问题及其解决方案希望能帮你快速定位问题。5.1 认证失败401 Unauthorized这是最常见的问题。命令行错误信息可能比较模糊比如MetaWeblog API Error或Authentication failed。排查步骤检查用户名和密码确保config.json里的username和博客园登录名一致。最关键的是password必须使用博客园后台“安全设置”里为 MetaWeblog API 生成的“客户端密码”而不是你的账户登录密码。去后台重新生成一个然后更新配置文件。检查 API URL确认url的格式完全正确https://rpc.cnblogs.com/metaweblog/你的用户名。注意是https不是http。用户名大小写敏感必须和博客地址中的用户名一致。使用curl手动测试 API这是一个非常有效的调试手段。打开终端尝试用curl调用博客园的 MetaWeblog API 获取用户信息这是一个简单的只读操作用于测试连通性和认证curl -X POST https://rpc.cnblogs.com/metaweblog/your_username \ -H Content-Type: text/xml \ -d ?xml version1.0?methodCallmethodNameblogger.getUsersBlogs/methodNameparamsparamvaluestringappkey/string/value/paramparamvaluestringyour_username/string/value/paramparamvaluestringyour_password/string/value/param/params/methodCall注意将your_username和your_password替换为你的真实信息密码还是用那个客户端密码。appkey可以留空或用任意字符串博客园的 API 似乎不校验这个。如果返回一串包含你博客信息的 XML恭喜认证和网络都是通的问题可能出在 Hermes 的请求构造或文章数据上。如果返回401 Unauthorized或类似的错误那肯定是用户名或密码错了请回到步骤1仔细检查。如果连接超时或返回其他网络错误可能是网络问题或者 API 地址不对。尝试用浏览器直接访问https://rpc.cnblogs.com看看是否能打开可能会显示一个简单的页面或错误。5.2 发布失败500 Internal Server Error 或 “解析错误”当认证通过但发布文章时失败常常是因为发送给 API 的 XML 数据格式不符合博客园的要求。排查步骤启用 Hermes 的详细日志如果 Hermes 支持--verbose或--debug参数使用它。这可能会输出它即将发送的 XML 请求体。仔细检查这个 XML 结构。检查 Front Matter 和内容日期格式确保date字段是合理的 ISO 8601 格式。可以尝试简化日期比如只保留2023-10-27看是否解决问题。分类和标签博客园可能对分类和标签的数量、格式有要求。尝试只设置一个分类标签用英文逗号分隔的字符串如Hermes,博客园,自动化而不是配置文件中的数组格式。你需要调整frontmatter映射和你的 Markdown 文件头。例如在配置中设置tags: tags映射到字符串然后在 Front Matter 里写tags: Hermes,博客园,自动化。特殊字符检查文章标题和内容中是否包含 XML 特殊字符如,,。Hermes 应该会自动转义这些字符但有时可能出错。可以尝试发布一篇标题和内容都非常简单纯英文无符号的文章来测试。查阅博客园 API 文档和社区博客园官方关于 MetaWeblog API 的文档可能不详细。去博客园的社区、论坛或者用搜索引擎搜索“博客园 MetaWeblog 发布 500 错误”很可能有其他开发者遇到过类似问题并分享了解决方案。5.3 文章发布成功但格式错乱或摘要不对这个问题通常出现在内容转换和字段映射环节。排查步骤摘要问题确认你的 Markdown 文件中是否包含了!--more--分割线。如果没有Hermes 可能会把整篇文章的 HTML 都作为摘要发送导致博客园首页显示全文。如果有但位置不对摘要内容也会不对。HTML 格式错乱检查 Hermes 使用的 Markdown 转换器配置。确保gfm: true已启用以支持常见的扩展语法。发布后到博客园后台编辑文章查看 HTML 源代码。看看是不是出现了多余的p标签嵌套或者代码块没有正确转换为precode。这可能是转换器的问题。可以尝试在配置中更换或调整transformers。一个常见坑点有些 Markdown 转换器会为段落首尾添加p标签。但博客园的编辑器可能已经有一个外层的p或div容器。这可能导致双重包裹。如果发现格式奇怪可以尝试在配置中寻找是否有关闭自动段落包裹的选项或者在发布后手动删除多余的 HTML 标签。图片等媒体资源如果你的文章引用本地图片Hermes不会自动上传图片到图床。你需要确保图片链接是互联网上可访问的 URL例如使用七牛云、又拍云等图床或 GitHub 等可直连的地址。否则发布后图片会显示为 broken link。5.4 网络问题与超时在国内网络环境下偶尔可能会遇到连接博客园 API 超时的情况。解决方案重试机制Hermes 可能内置了简单的重试逻辑如果没有你可以考虑在发布脚本外层包裹一个重试循环比如使用bash脚本或Node.js脚本。调整超时设置查看 Hermes 的配置或源码看是否有设置 HTTP 请求超时时间的选项。可以适当延长超时时间。分段发布如果文章很多可以修改配置中的publish.concurrency为1并考虑分批次发布减少单次请求的压力和失败的影响范围。6. 进阶技巧与工作流集成解决了基本发布问题后我们可以追求更优雅的工作流。6.1 多环境配置与敏感信息管理把密码明文写在hermes.config.json里并提交到 Git 仓库是非常不安全的。我们可以通过环境变量来管理敏感信息。改造配置文件将hermes.config.json中的敏感字段替换为环境变量占位符。但 Hermes 的 JSON 配置可能不支持直接读取环境变量。一个更通用的方法是使用一个前置的脚本或工具来生成最终的配置文件。推荐方案使用dotenv和模板配置在项目根目录创建.env文件并加入.gitignoreCNBLOGS_USERNAMEyour_username CNBLOGS_PASSWORDyour_app_specific_password CNBLOGS_URLhttps://rpc.cnblogs.com/metaweblog/your_username创建一个配置模板hermes.config.template.json{ site: { url: ${CNBLOGS_URL}, username: ${CNBLOGS_USERNAME}, password: ${CNBLOGS_PASSWORD} }, ... }在发布前使用一个简单的脚本如 Node.js 脚本或envsubst命令来替换模板中的变量生成最终的hermes.config.json。使用envsubstLinux/macOS:# 确保已安装 envsubst通常随 gettext 包提供 envsubst hermes.config.template.json hermes.config.json使用 Node.js 脚本:// generate-config.js const fs require(fs); require(dotenv).config(); // 读取 .env 文件 const template fs.readFileSync(./hermes.config.template.json, utf8); const config template.replace(/\$\{(\w)\}/g, (_, key) process.env[key] || ); fs.writeFileSync(./hermes.config.json, config);然后运行node generate-config.js。这样真正的密码只存在于本地的.env文件中配置文件模板可以安全地提交到代码仓库。6.2 与 Git 和 CI/CD 集成自动化发布的终极形态是集成到版本控制和工作流中。本地 Git Hook你可以在本地 Git 的post-commit或pre-pushhook 中调用 Hermes 发布命令实现“提交后自动发布”。但这需要谨慎因为每次提交都会触发发布。GitHub Actions / GitLab CI 自动化更推荐的做法是在 CI/CD 流水线中实现。基本思路是将包含环境变量的 SecretsCNBLOGS_PASSWORD等配置到 CI 平台。在 CI 配置文件中如.github/workflows/publish.yml在构建步骤中安装 Node.js 和 Hermes。使用 Secrets 设置环境变量。运行你的配置生成脚本如上文的envsubst或 Node.js 脚本。执行hermes publish命令。可以配置为只有当main或master分支有新的推送并且_posts目录有变更时才触发发布。# .github/workflows/publish.yml 示例片段 name: Publish to Cnblogs on: push: branches: [ main ] paths: - _posts/** jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: Setup Node.js uses: actions/setup-nodev3 with: node-version: 18 - name: Install Hermes run: npm install -g hermes-blogger - name: Generate config from template run: | export CNBLOGS_URL${{ secrets.CNBLOGS_URL }} export CNBLOGS_USERNAME${{ secrets.CNBLOGS_USERNAME }} export CNBLOGS_PASSWORD${{ secrets.CNBLOGS_PASSWORD }} envsubst hermes.config.template.json hermes.config.json - name: Publish posts run: hermes publish6.3 处理图片等静态资源Hermes 本身不处理图片上传。一个完整的工作流需要搭配图床工具。推荐工作流写作时在 Markdown 中直接使用图床的最终 URL。你可以使用 PicGo 这样的工具配合 Typora 等编辑器实现截图后自动上传到图床并生成 Markdown 链接。发布时由于链接已经是最终的 URLHermes 发布时无需做任何额外处理。备份建议将原始图片文件也存放在项目仓库的某个目录如./assets/images中作为备份。可以在.gitignore中忽略它们或者使用 Git LFS 管理。如果你希望有一个更集成的方案可能需要编写自定义脚本在 Hermes 发布前扫描 Markdown 文件中的本地图片路径调用图床 API 上传并将路径替换为线上 URL。但这会复杂很多需要权衡收益。7. 总结与个人体会回顾整个 Hermes 接入博客园的过程它确实如我最初期待的那样将我从重复的发布操作中解放了出来。现在我的写作流程变得非常清晰在 Obsidian 或 VS Code 里用 Markdown 写好文章配上 Front Matter图片通过 PicGo 自动上传到图床。写完保存提交 Git。如果我想立即发布只需在终端运行一条hermes publish命令或者如果配置了 CI直接推送到main分支几分钟后文章就会出现在我的博客上。最大的收获不是工具本身而是通过解决配置和踩坑过程中遇到的问题让我对 MetaWeblog API 这个“古老”的协议、对博客园的后台机制、以及对 Node.js 工具链的配置管理有了更深的理解。那些看似恼人的“坑”——比如密码要用客户端专用密码、摘要分割线!--more--的必须性、分类标签的格式映射——一旦跨过去就变成了稳固的知识点。对于想要尝试的同学我的建议是耐心按照步骤来从最简单的配置和一篇测试文章开始。充分利用curl等命令行工具进行手动 API 测试这能帮你快速隔离问题是出在网络认证、API 接口还是数据格式上。仔细阅读 Hermes 的文档和源码如果有必要理解其配置项的含义。最后别忘了安全第一永远不要将密码等敏感信息硬编码在配置文件里提交到公开仓库。Hermes 可能不是唯一的选择也不是最完美的选择但它以一种足够简单、可定制的方式解决了我的核心痛点。技术工具的价值最终体现在它是否能无缝融入你的工作流并让你更专注于内容创作本身。至少目前Hermes 做到了。