ONVIF 的技术栈是四层叠加:HTTP 传、SOAP 装、WSDL 描述、Profile 分级。 一条最干净的请求里,真正表达「我要什么」的只有 27 个字节,不到 7%。
上一节讲了 ONVIF 的来由, 这一节拆它的技术栈——四层各管什么,以及叠起来之后一条报文长什么样。 这四层在第六章都单独讲过,这里是把它们摞起来看。
一、四层叠加,各管一段
| 层 | 技术 | 管什么 | 对应小节 |
|---|---|---|---|
| 传输 | HTTP/1.1 | 把字节送到对端 | 06.01.02 |
| 装帧 | SOAP 1.2 | 把「调用」装进信封 | 06.01.05 |
| 描述 | WSDL 2.0 | 说明有哪些操作、参数什么类型 | 06.01.04 |
| 分级 | Profile | 声明「这个品类必须实现哪些」 | 07.01.04 |
前两层是「怎么发」,后两层是「发什么」。 这个划分很重要: 调不通时先判断是哪一半的问题—— 连不上是传输层,连上但报错是装帧层,报错说「不认识这个方法」是描述层。 第四层不出现在报文里,它只出现在产品彩页和一致性测试报告里。 所以它不影响「能不能调通」,只影响「该不该调」。
二、一条请求的字节去哪了
Demo 把一个 GetDeviceInformation 请求拆成三段数:
| 段 | 内容 | 字节 | 占比 |
|---|---|---|---|
| HTTP 头 | 请求行 + 两个头 | 204 | 50% |
| SOAP 信封 | Envelope + Body + 命名空间声明 |
181 | 44% |
| 业务元素 | <tds:GetDeviceInformation/> |
27 | 7% |
总请求 412 字节,真正表达意图的只有 27 字节。 这就是 RPC 的成本结构:大头是「怎么把这件事说清楚」,不是「说的事」。 第一行占了整整一半,而且全是固定开销——路径长一点、Host 长一点,它就涨。 所以「把设备地址配成域名而不是 IP」,请求会更大, 虽然只多几十字节,但在高频轮询里是实打实的。
三、加鉴权之后翻倍
ONVIF 的鉴权信息放在 SOAP 的 Header 里(WS-Security),不在 HTTP 头里。
所以它算在第二段,直接让信封翻倍:
| 版本 | XML 字节 | 相对最小版 |
|---|---|---|
| 不带鉴权 | 208 | 1.00 倍 |
| 带 UsernameToken | 451 | 2.17 倍 |
多出来的 243 字节,比整条原报文还长。
其中绝大头是那个 xmlns:wsse= 的命名空间 URI——光它就有七十多个字符。
这是 SOAP 命名空间机制的直接代价:每个新前缀都要把完整的 URI 抄一遍,
不能像 XML 的实体那样定义一次全局复用(除非用外部 DTD,而 SOAP 不允许)。
所以工程上有个共识:轮询能少发就少发,用事件订阅(PullMessages)代替定时查询,
这不只是省带宽,也是省设备的 CPU(07.02.11 讲)。
四、响应比请求大得多
请求 424 字节,响应 549 字节(同一台迷你设备)。
真实设备上这个比例更悬殊:GetProfiles 的响应经常上万字节,
因为一个 Profile 要列全套编码参数。
| 操作 | 请求 | 响应 | 倍数 |
|---|---|---|---|
GetDeviceInformation |
424 | 549 | 1.3 |
GetCapabilities |
414 | 782 | 1.9 |
GetServices |
406 | 1255 | 3.1 |
GetProfiles |
405 | 1174 | 2.9 |
第三、四行的倍数最高,因为它们返回的是列表——列表里每多一项就多一整段 XML。 这个不对称有个实际影响:设备的「上行带宽」比「下行」更吃紧,因为响应总是比请求大。 做多设备轮询时,瓶颈通常在设备侧的上行,不在客户端侧的下行。
五、动手 Demo:一个 ONVIF 请求的字节解剖
Demo 手工拼出两条请求(一条最小、一条带鉴权头), 分别量 HTTP 头、SOAP 信封、业务元素三段的字节数。 然后用真发的请求核对一遍——发出去的和算出来的要一致,不一致就说明算错了。
inner_min = "<tds:GetDeviceInformation/>"
xml_min = S.body_of("tds", inner_min) # 信封 + 业务元素
# 带 WS-Security 的 UsernameToken(形状照 ONVIF,不带摘要)
inner_auth = ("<s:Header><wsse:Security xmlns:wsse="
'"http://docs.oasis-open.org/wss/2004/01/'
'oasis-200401-wss-wssecurity-secext-1.0.xsd">'
"<wsse:UsernameToken><wsse:Username>admin</wsse:Username>"
"<wsse:Password>12345</wsse:Password>"
"</wsse:UsernameToken></wsse:Security></s:Header>"
"<tds:GetDeviceInformation/>")
print(len(xml_min.encode()), len(xml_auth.encode())) # 208 451
print(len(inner_min.encode())) # 27
实跑输出:
--------------------------------------------------------------------
一个 ONVIF 请求的字节解剖
--------------------------------------------------------------------
**前面第六章量过「包装」的代价,这一节把它拆得更细。**
一个 `GetDeviceInformation` 请求,**字节都花在哪了。**
**先看「最干净」的一条请求,分三段数:**
段 内容 字节 占比
------------------------------------------------------------------------------
HTTP 头 请求行 + 两个头 204 50%
SOAP 信封 `Envelope` + `Body` + 命名空间声明 181 44%
业务元素 `<tds:GetDeviceInformation/>` 27 7%
**「业务元素」那段只有 27 个字节**,**总请求 412 字节,也就是说真正表达「我要什么」的不到 7%。**
**这就是 RPC 的成本结构**:**大头是「怎么把这件事说清楚」,不是「说的事」。**
**加一个鉴权头,再看涨多少:**
版本 XML 字节 相对最小版 多出来的是什么
--------------------------------------------------------------------------------
不带鉴权 208 1.00 倍 —
带 UsernameToken 451 2.17 倍 **用户名 + 密码 + 一长串 xmlns**
**鉴权头多花 243 字节,比整条 XML 原报文(208 字节)还长。**
**其中绝大头是那个 `xmlns:wsse=` 的命名空间 URI**——**光它就有七十多个字符。**
**这也是为什么每次轮询都带着它,流量会翻倍**:**设备越多、轮询越密,这笔开销越显眼。**
**看一眼真实发出去的两条请求,长度差多少:**
`http://www.onvif.org/ver10/device/wsdl/GetDeviceInformation`
**HTTP 头 204 字节 + 信封 208 字节 = 总 424 字节**
**这个 424 字节的请求,拿回来的响应是 549 字节。**
**一来一回,为了五个字段,花了将近一千字节。**
鉴权头里我用的是明文密码,
这只是为了量字节——真 ONVIF 要的是 PasswordDigest(Base64 的 SHA1 摘要),
那段密文还更长(08.01.05 讲怎么算)。
「业务元素 27 字节」这个数是纯元素本身,不含它前面的信封。
这种口径必须写清楚,否则「27 字节」和「412 字节」两个数字看起来会互相矛盾。
最后那段「真发一次,核对长度」是这一节的自检:
算出来 412,发出去 424,差的 12 字节是 Host 头里的端口——
端口是运行时才分配的,算的时候还没定,所以算出来的少 12 个字节。
这个差异是我事后核对出来的,不是猜的。
30 秒实验
- 把 Host 从 IP 改成域名,重算请求字节,看涨多少。
- 给信封加一层
Header但不放任何内容,看多几个字节(<s:Header/>是 13 字节)。 - 把
GetProfiles的响应字节除以请求字节,和GetDeviceInformation比一比。
常见误区
- 以为鉴权信息放在 HTTP 头里。 ONVIF 的鉴权在 SOAP 的
Header里, 所以它算在 XML 那一半,不在 HTTP 那一半。 - 以为请求和响应差不多大。 响应通常是请求的 1.3 到 3 倍,返回列表的操作倍数最高。
- 以为算出来的字节数一定等于发出去的。 端口、时间戳、随机数这类运行时才定的字段会让两边对不上,差几十字节是正常的。
自测三问(点开对答案)
1. ONVIF 的四层技术栈分别是什么? —— HTTP(传输)、SOAP(装帧)、WSDL(描述)、Profile(分级)。 **Profile 不出现在报文里**,只出现在产品声明和测试报告里。 2. 为什么鉴权会让报文翻倍? —— 因为鉴权头里的 **`xmlns:wsse=` 命名空间 URI 有七十多个字符**, **加上用户名密码元素,一共 243 字节,比原报文还长。** 3. 响应总是比请求大,这对工程有什么影响? —— **设备的上行带宽比下行更吃紧。** 做多设备轮询时,**瓶颈在设备侧上行,不在客户端下行。**下一节把「十几组接口」拆开看:ONVIF 到底有多少个 service,每组管什么。
- ☐ (本节完,下一节 07.01.03 ONVIF规范)