生成 ONVIF 代码的第一步不是装工具,是下文件。 14 个 service WSDL 加 2 个 schema,合计 1.35 MB, 而官方站点的路径有三种写法,拼错就静默拿到 404 页面。
第七章把 ONVIF 的 service 和操作讲完了, 那是「协议长什么样」;第八章开始动手,这一节是「先把原料备齐」。 工程上这一步没有技术含量,但它是整章唯一不可跳过的一步—— WSDL 缺一个,后面所有命令都跑不通,而且报错信息看不出来缺哪个。
一、WSDL 到底是干什么用的
一句话:它是「服务的说明书」,而且是给工具读的说明书。 人看的是手册,工具看的是 WSDL——两者的区别在于 WSDL 里每个字段都带类型和顺序, 机器可以照着它生成 C 结构体。
| 文件 | 给谁看 | 里面有什么 |
|---|---|---|
| WSDL | 工具(wsdl2h) | 操作名、参数、返回、命名空间 |
| XSD | 工具(wsdl2h) | 数据类型定义 |
| PDF 规范 | 人 | 业务语义、状态机、异常 |
第三行不能替代前两行:规范里写的「这个字段可空」在 WSDL 里是 minOccurs="0",
而规范里那句「建议不要频繁调用」在 WSDL 里完全没有。
所以做 ONVIF 开发,规范和 WSDL 要对着看——WSDL 告诉你「怎么发」,规范告诉你「该不该发」。
二、这 16 个文件各管什么
下载清单里最容易被忽略的是那两个 xsd,因为它们的名字看起来像「附属品」,其实是主力:
| 文件 | 字节 | 地位 |
|---|---|---|
onvif.xsd |
432227 | 所有数据类型,最大的一份 |
common.xsd |
19528 | 公共基础类型 |
devicemgmt.wsdl |
199759 | 设备管理,根 |
media10.wsdl |
175142 | 媒体 ver10 |
media20.wsdl |
152275 | 媒体 ver20(Media2) |
| 其余 11 个 | 1 万~7 万 | 云台、事件、图像、分析等 |
第一行比第二行大二十多倍,这不是巧合:ONVIF 的数据类型全堆在 onvif.xsd 里,
而每个 service 的 WSDL 只引用其中一部分。
所以「只下 WSDL 不下 xsd」是跑不通的——
wsdl2h 会在解析 xsd:import 时停下来,报的是「找不到 onvif.xsd」,而不是「类型未定义」。
这个报错其实很友好,比后面那些「未定义类型」好查得多。
三、路径不统一这件事
官方站点的 WSDL 有三种路径形状,而文档里往往只给文件名,不给完整 URL:
| 形状 | 例子 | 个数 |
|---|---|---|
| 三段目录 | /ver10/device/wsdl/devicemgmt.wsdl |
8 |
| 两段直挂 | /ver10/recording.wsdl |
6 |
| 特例 | 目录 device、文件 devicemgmt |
1 |
第二行那 6 个是「照规律拼必错」的那批:
录像、检索、回放、接收器、显示、设备 IO,全部直接挂在版本目录下,没有 /wsdl/ 子目录。
第三行更离谱:device 与 devicemgmt 是两个不同的词,
照「目录名=文件名」的规律拼,一样错。
正确的做法是去官网的 specifications 页面抄链接,不要自己拼——页面上的链接是唯一的权威。
四、200 不等于下载成功
这是本节最该记住的一条。 我把 6 个地址拼错,服务器全部返回 HTTP 200,返回体是同一个 72906 字节的 HTML 页面—— 那是它的 404 页面,只是用 200 送出来的。
| 判据 | 可靠吗 | 说明 |
|---|---|---|
| HTTP 状态码 | 不可靠 | 这个站点对不存在的路径也回 200 |
| 文件大小 | 半可靠 | 72906 可疑,但别只认一个数 |
| 前 5 个字节 | 可靠 | <?xml 才算 WSDL |
第三行是唯一可信的判据:XML 文件一定以 <?xml 开头,
HTML 文件以 <!DOCTYPE 或 <html 开头。
两行代码就能判断,比看大小、看状态码都靠谱。
这个坑在别的地方也一样:很多「下载成功但打不开」的文件,都是把错误页当成了数据。
五、本机这一节的实测边界
这 16 个文件是我真下载的,字节数来自磁盘,不是抄文档。 但有三件事我没做到,如实说明:
| 项 | 做到了吗 | 说明 |
|---|---|---|
| 下载 16 个文件 | 做到了 | 字节数与耗时都是真的 |
| 确认是最新版 | 没做到 | 站点不给版本号,只能按内容判断 |
| 校验官方哈希 | 没做到 | 官网上没有提供 sha256 |
第二行要解释一下:WSDL 会随规范更新, 但 URL 不变、页面不写版本——所以「昨天下的和今天下的不一样」是可能的, 这也是为什么工程上要把 WSDL 一起入库,而不是每次构建都去下。 第三行是安全上的遗憾:没有官方哈希,就没法验证文件没被改过, 只能靠 HTTPS 和「第一次下载后锁进版本库」来保证一致性。
六、动手 Demo:16 个文件下下来,先看账单
Demo 读本机真实下下来的这 16 个文件,量字节、抽命名空间、验真假。
重点看两件事:onvif.xsd 有多大、6 个假货怎么识别。
# ① 逐个量字节(本地文件,不联网)
for fn in ("devicemgmt.wsdl", "media10.wsdl", "onvif.xsd"):
print(fn, os.path.getsize(os.path.join(W, fn)))
# ② 判真假:只看前 5 个字节
def verdict(p):
with io.open(p, "rb") as f:
return f.read(5).startswith(b"<?xml")
print(verdict("_wsdl35/devicemgmt.wsdl")) # True
print(verdict("_wsdl35/_wrong_replay.html")) # False
实跑输出:
--------------------------------------------------------------------
16 个文件下下来,先看账单
--------------------------------------------------------------------
**第八章第一步是把 ONVIF 的接口描述文件抓到本地。**
**官方给的是一张清单不是一个包**:14 个 service WSDL 加 2 个 schema,得逐个下。
**下面这些字节数是本机真下载后量的,不是抄文档。**
文件 字节 管什么
------------------------------------------------------
`devicemgmt.wsdl` 199759 设备管理(**根**)
`media10.wsdl` 175142 媒体 ver10
`media20.wsdl` 152275 媒体 ver20(Media2)
`ptz10.wsdl` 31969 云台 ver10
`ptz20.wsdl` 62047 云台 ver20
`event.wsdl` 48358 事件
`imaging.wsdl` 26756 图像
`analytics.wsdl` 34002 分析
`recording.wsdl` 62051 录像
`search.wsdl` 54129 检索
`replay.wsdl` 10754 回放
`receiver.wsdl` 16991 接收器
`display.wsdl` 24385 显示
`deviceio.wsdl` 66199 设备 IO
`onvif.xsd` 432227 **所有数据类型**
`common.xsd` 19528 公共基础类型
**合计 1416572 字节,约 1.35 MB。**
**最大的不是 WSDL 是 `onvif.xsd`**:432227 字节。
**因为所有数据类型都堆在里面**:459 个 `complexType`、99 个 `simpleType`、1183 个 `element`。
**而一个 service 的 WSDL 只用其中一部分**,所以「下 WSDL 不下 xsd」是搬不动的。
**然后是这一节真正要记住的教训。**
**ONVIF 官网的 WSDL 路径不统一**,两种形状:
形状 例子 个数
----------------------------------------------------------------
三段目录 `/ver10/device/wsdl/devicemgmt.wsdl` 8
**两段直挂** `/ver10/recording.wsdl` **6**
**例外** 目录叫 `device`,文件叫 `devicemgmt` 1
**第二行那 6 个是这一节的主角**:录像、检索、回放、接收器、显示、设备 IO,
**它们不在 `/wsdl/` 子目录里,直接挂在版本目录下。**
**我按「全都三段」的假设拼了这 6 个,全错。**
**第三行是连规律都算不上的特例**:`device` 与 `devicemgmt` 是两个词。
**错得多离谱?看返回体:**
**6 个错误地址,HTTP 状态码全是 200,返回体全是 72906 字节的同一个 HTML 页面。**
**这就是「能打开不等于能工作」的又一个实例**:服务器把 404 页面用 200 吐回来了。
**所以下载完必须验内容,不能看状态码**:
`devicemgmt.wsdl` 的前 5 个字节 → XML,能用
`_wrong_replay.html` 的前 5 个字节 → **HTML,假货**
**判据就一条**:前 5 个字节是不是 `<?xml`。
**是就当 WSDL 用,不是就说明地址错了**,别往下走。
第二段那两行是这一节真正有用的代码:判真假只看 5 个字节,比看大小、看状态码都可靠。
因为假的返回体是 HTML,它可能有一模一样的长度(我这次 6 个全是 72906 字节),
但开头永远是 <!DOCTYPE 或 <html。
注意 onvif.xsd 那个 432227,
比 devicemgmt.wsdl 的 199759 还大一倍多——这个数字是判断「有没有下全」的最快指标:
如果它只有几十 KB,说明下到的是别的东西。
最后那句「合计 1416572 字节」是 16 个文件之和,约 1.35 MB——这个体积说明一件事:
ONVIF 不是一个「轻量协议」,它的接口面比很多人以为的大得多。
30 秒实验
- 把
verdict()改成读 8 个字节,看能不能连 BOM 一起识别(UTF-8 BOM 是EF BB BF)。 - 去官网 specifications 页面数一遍,看能不能找出第 15 个 service。
- 把这 16 个文件的总字节数除以 1024 两次,看和 1.35 MB 差多少。
常见误区
- 看到 HTTP 200 就以为下成功了。 这个站点对不存在的路径也回 200, 返回的是 72906 字节的 HTML 页面。
- 只下 WSDL 不下 xsd。 所有数据类型都在
onvif.xsd里,少了它wsdl2h第一步就停。 - 按规律拼 URL。 6 个 service 是两段直挂,
device与devicemgmt还是两个词, 拼必错。
自测三问(点开对答案)
1. 为什么 `onvif.xsd` 比任何一个 WSDL 都大? —— **因为所有数据类型都定义在它里面**,**每个 service 的 WSDL 只是引用其中一部分。** 2. 怎么判断下到的是 WSDL 还是错误页? —— **只看前 5 个字节是不是 `下一节建工作空间:五个目录,建错位置不影响生成,但影响后面所有命令。
- ☐ (本节完,下一节 08.01.02 新建工作空间)