📹 第八章 ONVIF框架代码案例应用
📄 一句话概括

生成 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 秒实验

  1. 把 verdict() 改成读 8 个字节,看能不能连 BOM 一起识别(UTF-8 BOM 是 EF BB BF)。
  2. 去官网 specifications 页面数一遍,看能不能找出第 15 个 service。
  3. 把这 16 个文件的总字节数除以 1024 两次,看和 1.35 MB 差多少。

常见误区

  1. 看到 HTTP 200 就以为下成功了。 这个站点对不存在的路径也回 200, 返回的是 72906 字节的 HTML 页面。
  2. 只下 WSDL 不下 xsd。 所有数据类型都在 onvif.xsd 里,少了它 wsdl2h 第一步就停。
  3. 按规律拼 URL。 6 个 service 是两段直挂,device 与 devicemgmt 还是两个词, 拼必错。
自测三问(点开对答案) 1. 为什么 `onvif.xsd` 比任何一个 WSDL 都大? —— **因为所有数据类型都定义在它里面**,**每个 service 的 WSDL 只是引用其中一部分。** 2. 怎么判断下到的是 WSDL 还是错误页? —— **只看前 5 个字节是不是 `

下一节建工作空间:五个目录,建错位置不影响生成,但影响后面所有命令。

  • ☐ (本节完,下一节 08.01.02 新建工作空间)

相关笔记