普通人自建基于 WiFi Calling 的通讯网络能否行得通
Tag WiFi-Calling, 语音通话, 通讯, on by view 0

写于:2026 年中 一句话结论:不行。 普通人没有合法、可行的通道走”运营商级 WiFi Calling”。技术上被三重锁死,第一道且最硬的一道就是 eUICC 证书信任链——私有证书行不通,这是硅片级的死结。能做的最远边界是应用层 VoIP over WiFi那不是 WiFi Calling


0. 写这篇文章的动机

我最近在做一个 SGP.22 SM-DP+ 的开源实现,仓库叫 sm-dp,目标是把”用户从二维码触发 eSIM Profile 下载”这条链路完整跑通。几个月时间,我把 ES9+ 第一步 initiateAuthentication 写完、容器化、跑通 HTTPS、跑通 nginx 反代、修了一遍又一遍的协议头(大小写不敏感 + 多版本协议号支持),最后 MiniLPA 真的把请求发到我服务器上,sm-dp 返回 HTTP 200 + 标准失败 envelope,错误码 subjectCode 8.8.4 / reasonCode 3.7,信息是:

“The SM-DP+ has no CERT.DPauth.ECDSA signed by a CI Public Key supported by the eUICC”

这一行错误信息不是 bug,不是协议实现不对,不是网络问题。它就是答案:eUICC 里没有能信任我 SM-DP+ 证书的 CI 公钥。

撞墙的位置:eUICC 证书信任链

我把这条墙讲清楚,再回答”那能不能自建 WiFi Calling”这个问题。


1. 先把两件事分清楚:运营商 WiFi Calling ≠ 应用层 VoIP over WiFi

读者里肯定有人把这两个当回事,所以我必须先拆开:

运营商 WiFi Calling(VoWiFi) 应用层 VoIP over WiFi
信令 IMS SIP(P-CSCF / S-CSCF / I-CSCF / TAS) App 自有协议(APNs / Signal Protocol / 自建 WS)
鉴权凭据 ISIM @ UICC(SIM 卡里那个 SIP Digest-AKA 凭据) App 账户 / 设备证书
寻址 E.164 MSISDN(手机号) App ID / UUID / 自编号
接入网 不可信 WiFi + IPsec/IKEv2 → ePDG → EPC/5GC → IMS 任何 IP 承载,裸 socket
通话对象 跨运营商经 IPX / IBCF 进 PSTN 私域;想进 PSTN 需 SIP Trunk
紧急呼叫 E.112 / E.911 路径(受 PLMN 管制) 通常无合规紧急呼叫能力
计费 / 合法监听 运营商 CDR + LI 合规 App 厂商服务器侧,不在运营商 CDR
在手机拨号盘里 是,作为运营商主叫 不是,仅 App 自己的来电界面

运营商WiFi Calling / VoWiFi 是一个 3GPP 规范的术语,本质是”把 IMS 语音搬到不可信 WiFi 上”。它不是”用 WiFi 打电话的 App”。两者在协议层完全平行,互不相通

读者能做的最远边界——也是我自己正在做的——是右列那一条。那不是 WiFi Calling。这一点必须先说死,不然下面没法讲。


2. 第一道锁(也是最硬的一道):eUICC 证书信任链无法自建,私有证书就是不行

这一节是整篇文章最重要的一节,我会写得很慢。

2.1 我手里这块 eUICC 里到底有什么

我用的是一块 Eastcompeace(东信和平)生产、GSMA SAS 编号 ED-ZI-UP-0826 的消费级商用 eUICC。svn 是 2.2.2,euiccFirmwareVer 4.2.0。我用 MiniLPA 读出 EUICCInfo2,展开 euiccCiPKIdListForVerification

euiccCiPKIdListForVerification: [
  "81370f5125d0b1d408d4c3b232e6d25e795bebfb",  // GSM Association - RSP2 Root CI1
]
euiccCiPKIdListForSigning: [
  "81370f5125d0b1d408d4c3b232e6d25e795bebfb",  // GSM Association - RSP2 Root CI1
]

就一项。不是”列表里主要是 GSMA,但也可以有别人”——是只有一项

这一项是 GSM Association - RSP2 Root CI1 的公钥指纹。整张芯片一辈子就认这一个 CI。它的公钥在 eUICC 出厂时被一次性烧入 eUICC 内部的 ECASD(Embedded Certificate Authority Security Domain)—— ECASD 是 eUICC 的 JavaCard 安全元件里专门管理证书链的应用。这个烧入是 OTP(一次性可编程)或同等强度的写保护,软件层面改不了。

2.2 我试过”绕过”,结果就是不行

我 OpenSSL 生成了一对 ECDSA P-256 私钥,自签了一张 CI 证书,role OID 用 id-rsp-ci1.3.6.1.4.1.46898.3)。再用这张自签 CI 给 SM-DP+ 签了一张 CERT.DPauth.ECDSA,role OID 用 id-rsp-dp-authentication。我把 SM-DP+ 跑起来,让 MiniLPA 触发下载。

协议层面一切正常POST /gsma/rsp2/es9plus/initiateAuthentication 200 OK,所有握手都过,serverCertificate 也下发了。但真正的 Profile 下载在 ES10b 阶段被 eUICC 拒接——eUICC 拿到 serverCertificate 后会沿着 DPauth → CI → GSMA Root CI1 做链式验签,发现”这张 DPauth 是由一张不在我信任集的 CI 签的”,链路到我的自签 CI 时断了,回退到根时对不上,于是拒接。

报错就是上面那个 8.8.4 / 3.7:”无 CI 信任的 ECDSA 证书”。

2.3 一个常见误区:”装个根证书到手机能不能绕过”

有人问过我:”那我把 GSMA Root CI1 的证书装到手机的系统信任根里,不就解决了吗?”

不行。这是一个典型的认知误区,原因有两个:

第一,iOS / Android 的”系统信任根”只管 TLS / HTTPS 客户端校验,跟 eUICC 完全无关。iOS 上你装一个企业 CA 根证书,它影响的是 Safari / Mail / 第三方 App 怎么验 HTTPS 服务器。Android 7+ 默认连用户 CA 都不信,要 root 才能让 App 默认信用户 CA。但 eUICC 是独立的 JavaCard 安全元件,跟主系统隔离,主系统的”信任根”管不到它。eUICC 验签用的是它自己烧死在 ECASD 里的那张 GSMA Root CI1 公钥,只此一份

第二,eUICC 的 ECASD 没有外部 APDU 写接口。ECASD 是 eUICC OS 厂商(Eastcompeace / Idemia / Thales 等)在工厂模式下用厂商签名固件装入的,运行态下不允许任何 APDU 修改它的信任列表。你能换的只有 Profile(普通应用),碰不到 ECASD。能”修改” ECASD 信任列表的唯一合法途径是 eUICC 固件更新——但固件更新包也得由 EUM(eUICC 厂商)私钥签发,EUM 的根又是 GSMA Root CI。走到哪里都绕回 GSMA

2.4 那”开发 / 仿真 eUICC”呢?—— 能绕,但用途有限

必须诚实补一刀:“绕”对部分 eUICC 是可以的。少数开发 / 仿真 eUICC 的 ECASD 是”软”的,工厂模式允许加载额外 CI 信任锚:

  • osmocom 系列(swp-euicc 等)
  • 某些 Idemia / Valid 测试卡(需通过厂商渠道申请,明确”测试模式”)
  • 纯软件仿真器(如某些 JavaCard 仿真器)

在这些卡上,你可以把自己生成的自签 CI 公钥塞进信任集,eUICC 就会信。但这些卡不是消费级 eUICC,不能用于任何商用场景(运营商商用网不识别它们)。它们的用途是:

  • 协议层验证(”我的 SM-DP+ 协议实现对不对”)✓
  • 端到端加密路径验证(”签名验签链路通不通”)✓
  • 真实商用 Profile 下载 ✗
  • 让消费级手机原生电话 App 把你的 SM-DP+ 当运营商 ✗

我手头这块 Eastcompeace 不在列。本文后面所有讨论都以”商用 eUICC”为前提。开发卡的”绕过”是另一篇文章的话题,不能混淆。

2.5 GSMA PKI 的真相

把上面这些事实落到 GSMA PKI 体系里看:

GSMA Root CI(公开信任锚,固化在每张合规 eUICC 的 ECASD)
    │ 由 GSMA Root CI 私钥签发
Sub-CI(也叫 CI)
    │ - EUM 厂商(Eastcompeace / Idemia / Thales / Valid / G+D 等)持有
    │ - 这些 CI 的公钥被它们出厂的 eUICC 信任
End-entity 证书:SM-DP+ / SM-DS / EUM

这张图的三个特征决定了”个人不可能”:

  1. Root CI 私钥不卖:GSMA Root CI 私钥物理隔离在 GSMA 金库里,没有任何合法出售渠道。任何说”出售 GSMA Root CI 私钥”的网站都是骗子。

  2. Sub-CI 只发给通过 SAS-SM / SAS-SDS 现场审计的企业:SAS 是 GSMA 的安全认证体系,SM(Subscription Management)针对 SM-DP+ 服务,SDS 针对 SM-DS。审计员是 GSMA 授权的第三方(BSI / atsec / TÜV 等),要查你的:

    • HSM(硬件安全模块,FIPS 140-2 Level 3 或同等),必须,不能把 SM-DP+ 私钥存成 PEM 文件塞进容器
    • 物理安保(双人控制、门禁、监控)
    • 密钥管理与备份方案
    • 站点隔离、网络隔离
    • 人员背景调查
    • 年度复审
  3. 审计周期和钱:从启动到拿证 6 到 12 个月,钱 六位数 USD 起步(HSM 几万到十几万 + 审计费 + 持续合规运维人力)。

任何个人 / 小团队,没有这条路

2.6 结论(这一节最重要的一句话)

eUICC 证书信任链是个人根本无法触碰的硅片级约束,私有证书行不通,这不是软件问题。

我在 sm-dp 里跑通 ES9+ 协议层之后撞上的墙,就是这堵墙。这堵墙在我手里这块 Eastcompeace 芯片上不可逾越,对任何商用 eUICC 都不可逾越,对所有 GSMA 体系内的”自建 SM-DP+“尝试都不可逾越。这是 eSIM 安全模型的核心:如果信任锚能由软件改写,整个体系就崩了。


3. 第二道锁:运营商 IMS 核心网不是你想接就能接

即便你解决了证书链(你做不到,但假设做到了),下一个墙是运营商 IMS 核心网

运营商 WiFi Calling 的完整链路是:

UE(手机)
   │  IPsec/IKEv2 隧道(SWu 接口,TS 33.402)
ePDG(运营商侧加密网关,Cisco / Ericsson / Nokia / Mavenir 商用产品)
   │  GTP / PMIPv6(3GPP TS 23.402 S2b / TS 23.501 非授信接入)
EPC / 5GC(核心网:MME / SGW / PGW / AMF / SMF / UPF)
   │  SIP(IMS 接入)
IMS 核心:P-CSCF → I-CSCF → S-CSCF → TAS → SBC
   │                                    │
   │                                    │ 媒体:RTP / SRTP(受 QoS 控制)
   ▼                                    ▼
HSS / UDR(用户数据库,存 ISIM 凭据)
   │ 跨运营商经 IBCF 进 IPX → 对端运营商 IMS → PSTN

相关 3GPP 规范锚点:

  • TS 23.228(IMS 总体)
  • TS 23.402(非授信非 3GPP 接入,ePDG / SWu / S2b)
  • TS 23.501 / 23.502(5G 系统架构,非授信接入归入 5GC)
  • TS 24.502(非授信接入的会话管理)
  • TS 33.402(IKEv2 / IPsec 安全)

IMS 凭据在 ISIM @ UICC——也就是 SIM 卡里的 SIP Digest-AKA 凭据。这意味着”号码”绑在 SIM 卡上,不绑在 App 上。你给朋友发个”我的 WiFi Calling 号码是 13800138000”,那个号码必须在运营商 HSS 里登记,必须有 ISIM 凭据,必须有对应的 SM-DP+ Profile 已下发到某张 UICC。这条链路没有任何一个环节是开放的

  • ePDG 是运营商专有设备
  • HSS/HLR 是运营商核心数据库
  • IBCF 是运营商间边界
  • IPX 是 GSMA 运营的 IP 交换网络(Equinix / Etisalat / Tata 是主要运营商),不接入散户

这是企业基础设施级别的封闭,普通人连”租一个 IMS”都做不到。


4. 第三道锁:iOS / Android WiFi Calling 入口是运营商 entitlement,不是用户开关

假设(不可能的假设)你前两关都过了,你的 SM-DP+ 把 Profile 下发到了某张 eUICC 上,你还需要 iOS / Android 在系统设置里亮出”WiFi 通话”开关

4.1 iOS

iOS 的 WiFi Calling 开关不是用户能强制打开的。它出现的条件是:

  1. 系统读到一张经过 Apple 审核的 carrier bundle / IPCC(carrier.plist + 配套 APN、IMS entitlement、号码映射)
  2. Modem 固件支持 IMS VoWiFi
  3. eUICC 上有对应运营商下发的 Profile

参考 Apple 官方文档:Use Wi-Fi calling on your iPhone。Apple 维护一个运营商审核流程,运营商必须提交自己的 carrier bundle 经 Apple 审核。散户的 carrier bundle 不会被审核

4.2 Android

Android 类似但更复杂。Android 11+ 的 IMS API(ImsService / ImsManager)是 AOSP 提供的接口框架,但实现必须由运营商提供

  • 运营商的 IMS 服务二进制(OEM / modem 厂商预装或系统镜像里)
  • carrier_config.xml / carrier_settings 配置文件(描述 PLMN、APN、IMS entitlement)
  • Modem HAL(QMI / RIL / IMS 调制解调器层)支持 IMS

参考 Android 官方文档:Wi-Fi calling

裸 AOSP / 第三方 ROM 没有这些运营商二进制,永远显示不出 WiFi Calling 开关。LineageOS / GrapheneOS / Pixel Experience 上你都不会看到这个开关。

4.3 平台权力

这一道锁的本质是平台权力——苹果和 Google 决定”哪个运营商能被点亮”。这不是开放接口,不是 SDK 调一调就能开。运营商必须:

  • 走 Apple 的 Carrier Bundle 审核流程
  • 与 Google 签 carrier entitlement 协议
  • 接受苹果 / 谷歌的合规审计

普通开发者、创业公司想绕过去?没门。


5. 应用层 VoIP 进不去 IMS

行,我们退一万步——不追求运营商 WiFi Calling,就做个 App 让你和朋友能语音通话。是不是就行了?

可以。但要清醒地知道,这条路是和 IMS 完全平行的另一条路:

  • FaceTime:信令走 APNs,媒体 P2P(ICE/STUN/TURN),完全不进运营商 IMS / ePDG / SIP / ISIM
  • WhatsApp / Signal / Telegram:应用层 E2EE(Signal Protocol 等),UDP/TCP/TLS 上的 proprietary 信令,不注册到 IMS,不用 ePDG,不读 ISIM
  • 我的 rtpd:自建 WebSocket 信令 + UDP RTP 媒体,phone-android / phone-ios 通过 UniFFI 调用 rtpd-sdk,跑的是 48 kHz Opus / G.711 PCMU over UDP RTP

这些应用在 App 层面 用 CallKit / VOIP Push 让锁屏体验接近原生电话——iOS 上 App 可以在锁屏弹出来电 UI,点击接听,CallKit 让通话显示在系统的”通话中”界面里。但媒体始终在 App 自己控制的实时连接里,不进运营商核心网,不被运营商 CDR 计费,不走 ePDG,不使用 ISIM 凭据。

GSMA 在 2018 年的一份白皮书里把这类服务统称为 OTT(Over-The-Top)VoIP,明确区别于运营商 VoWiFi:GSMA blog - OTT Calling Protocol Analysis

互通 PSTN 仍然需要 SIP Trunk + 落地号,回到运营商身份,绕不开。


6. GSMA SGP.22 “999” 是不是个人通道?

不是。这是个常见误解。

GSMA 在 SGP.22 体系里确实给非传统运营商 / 私有网络 / MVNO 保留了一个简化通道,对应 Apple iOS 上的”999 标识”。它的本质是:

  • 简化版 SAS-SM 合规(不是免除,仍然要 GSMA 注册 + 当地监管备案)
  • iOS PLMN 白名单(”999”是一个 MCC/MNC 范围,由 Apple 审核)
  • 走标准 SGP.22 协议(仍然是 GSMA Root CI 签发的 CI 链)

它的目标客户是:

  • 企业 / 园区 / 港口 / 矿区 / 校园的私有 5G/LTE 网络运营商
  • 有 ICP/ISP 资质的 MVNO
  • 政府 / 应急 / 国防通信

不是个人。仍然要法人主体,仍然要 GSMA 注册,仍然要合规审计。它降的是合规门槛,不是消除 GSMA PKI——这点要讲清楚。


7. “那我做私有 IMS 网不就完了?”——是的,企业可行,个人不是合适主体

有些读者看到上面可能会想:”既然问题在 IMS 核心网,那我自建一个 IMS 私有网给园区用不就行了?”

这条路技术上完全可行,且已经有很多商用产品。具体拓扑:

私有基站(small cell / 5G gNB)
私有 5GC:AMF / SMF / UPF
私有 IMS:CSCF / TAS / SBC / HSS
私有 ISIM / USIM 凭据 → 行业终端(防爆手机 / 三防 PDA / 工业模组)

商用方案提供商:Athonet、Celona、CoreNetwork Dynamics、Mavenir、华为、中兴、京信、佰才邦等。

能做什么

  • ✅ 园区内部打通:工人 A 给工人 B 走 IMS VoNR / VoLTE
  • ✅ 行业终端之间互联互通
  • ✅ 私有网络的 QoS / 紧急呼叫 / 计费 / 调度

不能做什么

  • ✗ 出园区打电话给北京/纽约/伦敦的朋友:仍要公网运营商 SIP Trunk + 落地号
  • ✗ 让消费级 iPhone / 普通 Android 原生电话 App 显示为你的私有运营商:需要 Apple / Google 审核 carrier bundle,要 GSMA PKI 颁发合法 SM-DP+ 证书链
  • ✗ 在淘宝上卖给个人用户:合规不允许

个人适不适合

  • 50–500 用户的企业场景:可走 Athonet / Celona / Mavenir 这类 SaaS 化方案,半年到一年部署完成,百万级人民币预算
  • 个人 / 小作坊:不合适。HSM + 现场审计 + GSMA 注册 + 当地工信部备案(频谱 + 电信业务资质),百万级设备和合规起步
  • 不要混淆:私有 IMS 网不是”WiFi Calling 替代品”,它是企业自建专网方案

结论:私有 IMS 是企业选项,不是个人 “WiFi Calling” 的替代品。


8. 我手头这套栈在整张图里是什么位置

让我把我自己跑的东西摆出来,给读者一个具象的”普通人能做的最远边界”:

┌──────────────────────────────────────────────────────────────┐
│ phone-android (Kotlin / Compose, 48 kHz Opus over UDP RTP)   │
│ phone-ios     (SwiftUI, G.711 PCMU over UDP RTP)            │
│       │                                                        │
│       │ UniFFI bindings                                        │
│       ▼                                                        │
│ rtpd-sdk (Rust)                                                │
│       │                                                        │
│       │ WebSocket signaling + UDP RTP                         │
│       ▼                                                        │
│ rtpd (Rust) ──── PostgreSQL(短号注册、状态)                  │
└──────────────────────────────────────────────────────────────┘

        完全在 IP 层之上,不进运营商 IMS / ePDG / ISIM
        类比:FaceTime / WhatsApp / Signal / 自建 SIP PBX
┌──────────────────────────────────────────────────────────────┐
│ MiniLPA (Kotlin 桌面 GUI)                                      │
│       │                                                        │
│       │ GSMA RSP 流程                                          │
│       ▼                                                        │
│ sm-dp (Rust / Rocket, SGP.22 SM-DP+)                         │
│   - ES9+ /gsma/rsp2/es9plus/initiateAuthentication ✓          │
│   - ES9+ /gsma/rsp2/es9plus/authenticateClient (待实现)        │
│   - ES9+ /gsma/rsp2/es9plus/getBoundProfilePackage (待实现)   │
│   - 卡在:ProfilePackagingProvider = UnavailableProvider      │
│   - 原因:没有 GSMA 签发的 CERT.DPauth.ECDSA                 │
└──────────────────────────────────────────────────────────────┘

左边那套(rtpd + phone-*)是”应用层 VoIP over any-IP”,我可以做,可以给你用,可以做完整加密协议,可以用 iOS CallKit 让体验接近原生电话。但它永远进不了运营商拨号盘

右边那套(sm-dp + MiniLPA)是”eSIM 个人化通道”,我可以做完整协议层,但永远拿不到 GSMA 签发的 SM-DP+ 证书,所以商用 eUICC 永远不信我。

这两个栈的交集:没有。它们解决不同的问题,互不替代。


9. 结论

TL;DR(再说一遍):普通人自建”运营商级 WiFi Calling”——不行。三重锁死:

  1. eUICC 证书信任链(首道锁,最硬) —— GSMA Root CI1 公钥烧死在 ECASD,私有证书行不通,软件改不了,这是硅片级的死结。
  2. 运营商 IMS 核心网 —— 凭据在 ISIM @ UICC,ePDG / HSS / IBCF / IPX 全部是企业级专有基础设施。
  3. iOS / Android WiFi Calling 入口 —— carrier entitlement + carrier bundle + modem 固件,平台权力决定谁能被点亮。

普通人能做的最远边界:应用层 VoIP over WiFi。它不是 WiFi Calling,不能进运营商拨号盘,不能跨运营商互通 PSTN 出园区,但仍能在 IP 范围内提供良好体验——我手头的 rtpd + phone-android / phone-ios 就是这个边界的一个真实案例。

“那能不能做私有 IMS 网?”——企业可以,个人不行,仍要 GSMA 注册 + 合规审计 + 法人主体。

“那 GSMA SGP.22 ‘999’ 是不是个人通道?”——不是。简化通道仍是企业通道,仍然走 GSMA PKI。

“那把 GSMA Root CI 装到手机系统信任根里能不能绕过?”——不能。iOS / Android 系统信任根管不到 eUICC,ECASD 是独立的 JavaCard 安全元件。

如果你想做”普通人能用的语音通话网络”,我的真实建议:

  • 不要碰 eSIM / SM-DP+ 这一条路,除非你是企业、愿意投百万级 + 半年到一年走 SAS-SM
  • 走应用层 VoIP——IP 网络上能跑通就好,iOS CallKit 让体验接近原生电话,体验上限就在这里
  • 要合法合规:不要碰真实 PSTN 互通,不要碰紧急呼叫责任,不要碰 PLMN 标识

如果你想做”私有 5G/LTE + 私有 IMS”——这是个百万级起步的企业项目,不是个人项目,请按企业路径走。


10. 参考资料


11. 写在最后

我搭 sm-dp 的初衷是”我想搞清楚 eSIM 到底是怎么工作的”。结果搞清楚之后,发现这条路对个人没有商用落点

搞清楚的过程本身有价值。我跑完了协议层,撞上了 eUICC 信任链这堵墙,写下这篇文章,至少能让下一个想”自建 eSIM 运营商”的朋友少走三个月弯路。

对普通开发者来说,应用层 VoIP over IP 仍然是 IP 网络上能做的事情里体验最好的一条路。iOS CallKit 让它看起来像电话,Signal Protocol 让它端到端加密,WebRTC 让浏览器免装 App。它不是运营商级 WiFi Calling,但它真正可用的语音通信。

这是我能给出的最诚实的答案。


windows live writer与wordpress通讯协议(xmlrpc)分析
Tag windows live writer, wordpress, xmlrpc, 通讯, on by view 5900

最近一直在完善自己的博客,wordpress博客不可不谓之博客系统中最完善的一个,我的博客系统也一直以wordpress为样本,向wordpress学习。相信用过wordpress的人都用过windows live writer作为自己博客的客户端。windows live writer原本是微软为live博客开发的客户端,但是现在live博客已经关停,因此windows live writer也停止了更新。作为windows系统下最佳的博客离线客户端,即便它已经停止更新,它也将会是一款经典的软件,如同xp系统一样。

最近两天的时间,我将自己的博客系统实现了与windows live writer通讯,苦于找不到有用的指导资料,折腾得很辛苦。

调试工具:
服务端:本地搭建wordpress,我的博客blog
客户端:windows live writer,chrome浏览器的Postman应用扩展

调试过程:

  1. 进入本地wordpress首页,找到xmlrpc协议入口

    <link title="RSD" rel="EditURI" type="application/rsd+xml" href="http://127.0.0.1/xmlrpc.php">

    之后的所有请求都是从这个入口上实现的。

  2. 协议检查。windows live writer连接后的第一件事请是获取到首页上的接口(title为RSD的link标签),第二件事情便是向http://127.0.0.1/xmlrpc.php发送get请求,获取到的内容大致如下:

    <?xml version="1.0" encoding="UTF-8"?><rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
      <service>
        <engineName>WordPress</engineName>
        <engineLink>http://wordpress.org/</engineLink>
        <homePageLink>http://127.0.0.1</homePageLink>
        <apis>
          <api name="WordPress" blogID="1" preferred="true" apiLink="http://127.0.0.1/xmlrpc" />
        </apis>
      </service>
    </rsd>
  3. 登录,发送blogger.getUsersBlogs请求【以下请求的主体均在http request的body内,并且皆为post请求】

    <?xml version="1.0" encoding="utf-8"?>
    <methodCall>
     <methodName>blogger.getUsersBlogs</methodName>
     <params>
      <param>
       <value>
        <string>ffffffabffffffce6dffffff93ffffffac29ffffffc9fffffff826ffffffdeffffffc9ffffffe43c0b763036ffffffa0fffffff3ffffffa963377716</string>
       </value>
      </param>
      <param>
       <value>
        <!-- 用户名 -->
        <string>lijun</string>
       </value>
      </param>
      <param>
       <value>
        <!-- 密码 -->
        <string>lijun</string>
       </value>
      </param>
     </params>
    </methodCall>

    响应:

    <?xml version="1.0" encoding="UTF-8"?>
    <methodResponse>
      <params>
        <param>
          <value>
            <array>
              <data>
                <value>
                  <struct>
                    <!-- 1 -->
                    <member><name>isAdmin</name><value><boolean>1</boolean></value></member>
                    <!-- homepage -->
                    <member><name>url</name><value><string>%s</string></value></member>
                    <!-- userid -->
                    <member><name>blogid</name><value><string>%d</string></value></member>
                    <!-- blogname -->
                    <member><name>blogName</name><value><string>%s</string></value></member>
                    <!-- xmlrpc url address -->
                    <member><name>xmlrpc</name><value><string>%s</string></value></member>
                  </struct>
                </value>
              </data>
            </array>
          </value>
        </param>
      </params>
    </methodResponse>

    上面的%d%s等按照自己的博客替换成相应的返回参数,遵循printf函数的格式化规则。

  4. 新建文章metaWeblog.newPost

    <?xml version="1.0" encoding="utf-8"?>
    <methodCall>
     <methodName>metaWeblog.newPost</methodName>
     <params>
      <param>
       <value>
        <string>1</string>
       </value>
      </param>
      <param>
       <value>
        <string>lijun</string>
       </value>
      </param>
      <param>
       <value>
        <string>lijun</string>
       </value>
      </param>
      <param>
       <value>
        <struct>
         <member>
          <name>title</name>
          <value>
           <string>test tag</string>
          </value>
         </member>
         <member>
          <name>description</name>
          <value>
           <string>&lt;p&gt;test tag content&lt;/p&gt;</string>
          </value>
         </member>
         <member>
          <name>mt_text_more</name>
          <value>
           <string />
          </value>
         </member>
         <member>
          <name>wp_slug</name>
          <value>
           <string />
          </value>
         </member>
         <member>
          <name>mt_basename</name>
          <value>
           <string />
          </value>
         </member>
         <member>
          <name>wp_password</name>
          <value>
           <string />
          </value>
         </member>
         <member>
          <name>categories</name>
          <value>
           <array>
            <data>
             <value>
              <string>ceshi</string>
             </value>
             <value>
              <string>tag</string>
             </value>
            </data>
           </array>
          </value>
         </member>
         <member>
          <name>mt_excerpt</name>
          <value>
           <string />
          </value>
         </member>
        </struct>
       </value>
      </param>
      <param>
       <value>
        <boolean>1</boolean>
       </value>
      </param>
     </params>
    </methodCall>

    响应:

    <?xml version="1.0" encoding="UTF-8"?>
    <methodResponse>
      <params>
        <param>
          <value>
          <!-- post id -->
          <string>%d</string>
          </value>
        </param>
      </params>
    </methodResponse>
  5. 新建分类标签请求wp.newCategory

    <?xml version="1.0" encoding="utf-8"?>
    <methodCall>
     <methodName>wp.newCategory</methodName>
     <params>
      <param>
       <value>
        <string>1</string>
       </value>
      </param>
      <param>
       <value>
        <string>lijun</string>
       </value>
      </param>
      <param>
       <value>
        <string>lijun</string>
       </value>
      </param>
      <param>
       <value>
        <struct>
         <member>
          <name>name</name>
          <value>
           <string>测试</string>
          </value>
         </member>
         <member>
          <name>parent_id</name>
          <value>
           <int>0</int>
          </value>
         </member>
        </struct>
       </value>
      </param>
     </params>
    </methodCall>

     响应:

    <?xml version="1.0" encoding="UTF-8"?>
    <methodResponse>
      <params>
        <param>
          <value>
          <!-- catalog id -->
          <int>%d</int>
          </value>
        </param>
      </params>
    </methodResponse>
  6. 新建媒体文件metaWeblog.newMediaObject【图片上传】

    <?xml version="1.0" encoding="utf-8"?>
    <methodCall>
     <methodName>metaWeblog.newMediaObject</methodName>
     <params>
      <param>
       <value>
        <string>1</string>
       </value>
      </param>
      <param>
       <value>
        <string>lijun</string>
       </value>
      </param>
      <param>
       <value>
        <string>lijun</string>
       </value>
      </param>
      <param>
       <value>
        <struct>
         <member>
          <name>name</name>
          <value>
           <string>loadfailed.png</string>
          </value>
         </member>
         <member>
          <name>type</name>
          <value>
           <string>image/png</string>
          </value>
         </member>
         <member>
          <name>bits</name>
          <value>
           <!-- base64转码的图片文件 -->
           <base64>iVBORw0KGgoAAAANSUhEUgAAAkJggg==</base64>
          </value>
         </member>
        </struct>
       </value>
      </param>
     </params>
    </methodCall>

     响应:

    <?xml version="1.0" encoding="UTF-8"?>
    <methodResponse>
      <params>
        <param>
          <value>
          <struct>
            <!-- file id -->
            <member><name>id</name><value><string>%d</string></value></member>
            <!-- file name -->
            <member><name>file</name><value><string>%s</string></value></member>
            <!-- file url -->
            <member>
              <name>url</name>
              <value><string>%s</string></value>
            </member>
            <!-- file type -->
            <member><name>type</name><value><string>%s</string></value></member>
          </struct>
          </value>
        </param>
      </params>
    </methodResponse>


协议的内容太多,如有需要还建议自己使用相关的工具进行捕捉请求,以及使用Postman捕捉响应,然后自己分析请求与响应的内容,并在自己的系统中实现它。响应部分的其他内容可以参考我的博客系统源码http://github.com/duguying/blog ,请求部分我已经打包可以直接下载