Skip to content

HTTP 驱动

dc3-driver-http 把任意 HTTP/REST 接口当作数据源接入 IoT DC3——周期性调用 REST 端点、从 JSON 响应里抽一个字段作为位号值,并支持用请求体模板向接口写值。读完你能判断哪些设备/平台适合用它接入、每个属性该填什么、接不通时从哪里查。

协议背景

HTTP(HyperText Transfer Protocol)与建立在它之上的 REST 风格接口,是互联网最通用的请求/响应协议:客户端用一个方法GET/POST/PUT/DELETE)对一个资源路径发起请求,服务端返回状态码与一段报文(在物联网场景里通常是 JSON)。它无连接语义简单、几乎所有语言和工具都原生支持、调试方便,因此成为系统间集成的"最大公约数"。

在物联网四层参考架构里,HTTP 属于网络层中的应用层消息协议一类(与 MQTT、CoAP、LwM2M 并列)——它定义" 消息长什么样、怎么投递",而不关心底层走的是 Wi-Fi 还是蜂窝。但要诚实地说:HTTP 报文头臃肿、保活成本高、不为受限设备设计,并不适合 电池供电终端的高频上报。它在 IoT 里的真正位置是对接现成接口——第三方平台开放的 REST API、设备自带的 RESTful 接口、把现场数据聚合成 HTTP 端点的数据网关。这类"上游已经讲 REST、只需周期取数"的场景,正是本驱动的用武之地。关于 HTTP 与 MQTT/CoAP/LwM2M 的取舍,见物联网网络层章节

本驱动作为 HTTP 客户端(驱动类型 DRIVER_CLIENT),用 Spring WebFlux 的 WebClient位号上配置的路径与方法去调接口,从 JSON 响应中按路径抽出一个值。两个本驱动特有的概念后面会反复出现:

  • 响应路径(Response Path):从响应 JSON 里定位某字段的简单点号路径,如 $.data.temperature 表示取 data 对象下的 temperature。留空则把整段响应原文作为值。
  • 请求体模板(Body Template):写值时用的请求体模板,里面的 ${value} 占位符会被命令参数替换成实际写入值。

属性配置

属性分两层填写:驱动属性driver-attribute,设备级,决定连到哪个服务)、位号属性point-attribute ,决定每个位号调哪个路径、用什么方法、取哪个字段——读和写都用这一份)。application.yml 里还声明了命令属性command-attribute),但当前 write() 不消费它(见下文命令属性小节)。三类属性的来历与覆盖关系见属性与配置 。所有默认值均取自驱动的 application.yml

驱动属性(设备级 driver-attribute

接入一个 HTTP 数据源时,在设备上填这些属性。它们决定连到哪个服务、带什么头、超时多久——同一台设备下所有位号共享这套连接参数:

属性code类型默认值说明
Base URLbaseUrlSTRING(空)API 请求的基础地址(如 https://api.example.com
MethodmethodSTRINGGET声明的默认 HTTP 方法,但当前实现未读取该属性(见下方告警);实际方法只由位号属性决定
HeadersheadersSTRING(空)自定义请求头,JSON 形式(如 {"Authorization":"Bearer xxx"}
TimeouttimeoutINT5000请求超时(毫秒),作用于响应超时 responseTimeout

baseUrl 是必填项——驱动用它构造 WebClient 的 base URL,所有位号路径都拼在它之后;缺了它驱动的 validate() 会直接判定校验不通过。 timeout 默认 5000 毫秒,落到 Reactor Netty HttpClientresponseTimeout 上。

Headers 属性目前不生效

headersapplication.yml 里已声明,但当前实现的 getConnector() 只为 WebClient 设置了固定的 Content-Type: application/json没有读取并应用 headers 属性。需要带 Authorization 等自定义头鉴权的接口,暂时无法仅靠该属性接入。

驱动级 Method 属性目前不生效

methodapplication.yml 里声明为驱动级属性,但 getConnector() 只读取 baseUrltimeout,从不读取驱动级 methodread()/write() 的方法只取自位号属性 method,缺省回退到硬编码的 GET。因此在设备上设 method=POST 不会生效——它与 headers 同属"已声明但未应用"的属性。HTTP 方法实际只由位号属性 method 决定。

位号属性(point-attribute

每个采集位号上填:调哪个路径、用什么方法、(写时)发什么请求体、从响应里取哪个字段。读/写实际使用的 HTTP 方法只来自位号的 method,缺省时回退到硬编码的 GET,与驱动级 method 属性无关(驱动级 method 不被实现读取,见上):

属性code类型默认值说明
PathpathSTRING(空)API 路径(如 /api/v1/sensor/{id}
MethodmethodSTRINGGET本位号的 HTTP 方法,缺省回退到硬编码 GET
Body TemplatebodyTemplateSTRING(空)${value} 占位符的请求体模板
Response PathresponsePathSTRING(空)从 JSON 响应抽值的路径(如 $.data.temperature

path 拼在 baseUrl 之后

实际请求 URL 是 baseUrl + path。例如 baseUrl=https://api.example.compath=/api/v1/sensor/1 ,驱动就请求 https://api.example.com/api/v1/sensor/1

Response Path 是简单点号路径,不是完整 JSONPath

驱动把 $. 前缀去掉后按 . 逐段从根对象往下钻,只支持 $.a.b.c 这样的逐层取字段写法。不支持数组下标([0] )、过滤器、通配符等完整 JSONPath 语法。取数组元素、或路径取不到对应字段时,会退回返回整段响应原文——这往往就是位号值" 看起来不对"的根因。响应本身就是裸值(纯数字/字符串)时,responsePath 留空即可,驱动把整段响应当作位号值。

写值要靠 Body Template 渲染

写命令不会自动把值塞进请求体。必须在位号的 bodyTemplate 里写好带 ${value} 的模板(如 {"value":${value}} ),驱动才会把命令参数替换进去发出;模板为空时发的是空请求体。

命令属性(command-attribute

命令属性目前不被写入路径消费

application.ymlcommand-attribute 下声明了 pathmethoddefault-value: POST),但驱动的 SPI write() 签名只接收 driverConfigpointConfig,不传入命令属性映射;write() 实际从位号属性(pointConfig)读取 path/method/ bodyTemplate,且 method 缺省回退到硬编码的 GET(不是 POST)。因此下表列出的 command-attribute 当前是声明但未生效的死配置,写操作的路径与方法请填在位号属性上。

下表为 application.yml 中的声明值(当前 write() 未读取):

属性code类型默认值说明
PathpathSTRING(空)命令的 API 路径(当前未被 write() 读取)
MethodmethodSTRINGPOST命令的 HTTP 方法(当前未被 write() 读取)

采集与健康检查

这些参数定在 application.ymldc3.driver.schedulehealth 下,无需在设备上填:

  • 采集周期application.yml 基线定时读 cron 0/30 * * * * ?(每 30 秒读一轮);默认激活的 dev profile 在 application-dev.yml 把 read cron 覆盖为 0/5 * * * * ?(每 5 秒),故开箱即用的实际采集间隔是 5 秒。
  • 健康检查:设备健康检查 cron 0/15 * * * * ?,租约超时 45 秒 ——在线状态机制见设备
  • 在线判定health() 以"clientMap 里是否为该设备建过 WebClient"判断在线——首次成功读/写后建立连接即视为在线;读/写抛异常时驱动会 clientMap.remove(deviceId) 摘除连接,下一轮重建。

故障排查

连不上 / 一直 offline

先确认 baseUrl 可达:用 curl <baseUrl><path> 在驱动所在主机直接验证网络与端口是否通。驱动以"是否建过 WebClient" 判在线,首次读/写失败会立即摘除连接,因此 baseUrl 错、DNS 解析不了、或目标端口被防火墙挡,都会表现为设备始终 offline。

请求超时

默认 timeout=5000 毫秒落在响应超时上。目标接口本身慢、或网络抖动时会触发超时并把本轮读/写判为失败、摘除连接。先用 curl -w '%{time_total}' 量一下真实耗时,确认是接口慢还是链路慢,再据此调大 timeout

位号值看起来不对 / 总是整段 JSON

多半是 responsePath 没匹配上。该驱动只认 $.a.b.c 的逐层点号路径,路径写错、字段名大小写不符、或想取数组元素( $.list[0].v),都会因取不到字段而退回返回整段响应原文。对照接口真实响应逐层核对字段名;要取数组里的元素,当前实现做不到。

鉴权接口 401/403

当前实现未应用 headers 属性(见上文驱动属性表的告警)。需要 AuthorizationX-Api-Key 等请求头的接口,暂时无法仅凭设备属性接入,会被服务端拒为 401/403。

写命令报错或没生效

写值经由位号的 bodyTemplate 渲染:模板为空时发的是空请求体,接口若要求 JSON body 会拒绝。确认 bodyTemplate 里含 ${value} 占位符、且渲染后是接口接受的合法 JSON;写失败时驱动抛 WritePointException 并摘除连接。

在 IoT DC3 中如何落地

  • dc3.driver.codeHttpDriver(驱动名 HTTP REST Client Driver,类型 DRIVER_CLIENT)。该 code 是稳定路由标识,不可随意改。
  • :✓ 已实现。定时按位号 path/method 调接口,responsePath 从 JSON 抽值。
  • :✓ 已实现。把位号 bodyTemplate${value} 替换为命令参数后发请求。
  • 订阅/上报:— 不支持。HTTP 是请求/响应模型,驱动主动发起,无被动推送通道。

以上读/写能力与驱动能力矩阵HTTP (HttpDriver) 行一致。

实现状态:可用

HttpDriverCustomServiceImplinitial()/read()/write()/health()/validate() 均已完整实现,是可投入采集的成熟驱动。两处实现边界须知:① responsePath 仅支持简单点号路径,不支持数组/过滤器(见上);② headers 属性已声明但尚未在连接中应用,自定义请求头当前无法生效。

最小接入示例

把一个返回 {"data":{"temperature":25.6}} 的接口接进来:

  1. HTTP REST Client Driver 创建设备,驱动属性填 baseUrl=https://api.example.commethod=GETtimeout=5000
  2. 给设备绑定的模板加一个温度位号pointTypeFlag=FLOATREAD_ONLY),位号属性填 path=/api/v1/sensor/1method=GETresponsePath=$.data.temperature
  3. 启动驱动,数秒内就能在位号值里看到抽取出的 25.6(默认 dev profile 每 5 秒采一轮)。

延伸阅读

基于 AGPL-3.0 协议发布