# HTTP

> HTTP 驱动参考：把 HTTP 与 HTTPS endpoint 当作点位来轮询、凭据、路径映射、响应体解析、用 PUT 写入，以及类型。

HTTP 驱动把**通用 HTTP endpoint**当作点位来轮询：一台自带小型 Web 服务器的局域网传感器、一个在固定 URL 上发布读数的网关、你自己写的一个服务。它是本产品里最简单的客户端模式驱动：**Ganter Lab 用普通的 GET 请求连到仪器上**，并把每一份响应体读作一个值。

有两条属性划出了它的适用范围：

- 传输是**设备自己的选择**。设备一律走 TLS 够到它的服务，直到它的**用普通 HTTP 发送**这一项另作交代；主机前面写上 `http://` 或 `https://`，就会把这一项拨到相应的位置，主机则只留下主机名本身，这样两者永远不会互相矛盾。无论哪一种，驱动都会在每一次请求上送出这台设备的凭据，可以是按 HTTP Basic 送的用户名和密码，也可以是一个承载令牌。[AVEVA PI](driver-aveva-pi) 和 [Redfish](driver-redfish) 这两个驱动为那两种服务另外带来的，是它们各自的词汇：PI 路径和 WebId、Redfish 的资源树，而这个驱动对此一无所知。
- **整个响应体就是那个值**。这个驱动不是 JSON 字段提取器：数值点位要求响应体本身就是那个光秃秃的数字。

## 连接字段 {#connection-fields}

| 字段 | 它是什么 | 格式 | 默认值 |
|---|---|---|---|
| 主机 | endpoint 的主机名或 IP 地址。主机前面写上 `http://` 或 `https://`，会把下面那一项传输拨到相符的位置，存下来的主机则不带它。主机后面写的端口（`:8080`）会移到端口字段，再后面的路径（`/api`）会移到资源路径，所以这里可以直接粘贴 `http://192.168.0.5:8080/api` 这样的完整地址。IPv6 地址保留方括号。 | 主机名、IP，或者两者之一前面加上 `http://` 或 `https://` | 空 |
| 端口 | TCP 端口。新设备让它留空，空框表示所选传输应答的那个端口：走 HTTPS 是 443，明文是 80。框里以灰色显示这个端口，并随传输的选择而变；以 0 保存的设备也是这样显示的。 | 1 到 65535，或留空 | 留空 |
| 资源路径 | 一段可选的路径前缀，放在**每一个**点位路径的前面，例如 `api/v2`。留空就不加前缀。 | 路径文本 | 留空 |
| 用普通 HTTP 发送 | 只把这一台设备从 HTTPS 降到明文 HTTP。不勾表示 HTTPS，凭据也就不会明晃晃地上线。面板会把后果说清楚：走明文 HTTP 时，请求，以及这台设备携带的任何凭据，都以未加密的方式传输。用于不接受其他传输方式的 endpoint。 | 开 / 关 | 关 |
| 用户名 | 用于 **HTTP Basic** 认证的账户，只在没有设承载令牌时才用。留空（并且没有令牌）会让请求以匿名身份发出。 | 自由文本 | 空 |
| 密码 | 和用户名配对的密码。在静态存储时按 Windows 用户保护；在别的 Windows 账户下输入的秘密会显示为读不出来，必须重新输入一次。 | 自由文本 | 空 |
| 承载令牌 | 在每一个请求上以 `Authorization: Bearer …` 发出的一个令牌。设了它就**压过**用户名/密码那一对。在静态存储时以同样方式保护。 | 令牌文本 | 空 |

连上时，驱动会对**配置的地址**（主机加资源路径）发一个 HEAD 请求来核实这个 endpoint，HEAD 没实现时退回用 GET；两者中任何一个成功应答，就算够得着。因此，一个根路径答 404、而 API 正常应答的服务算作在线，只要资源路径指的是那个 API。走 HTTPS 时，服务的 TLS 证书在 Windows 信任它，或你在本驱动页面的[现场设备访问](#equipment-access)里批准了这份证书本身时被接受。设备若被降到明文 HTTP，凭据就是明文传出去的，设备连上时工作站会把这一点写进连接器日志。每一个请求给十秒：一个接受了连接却不说话的 endpoint，代价是一次读数，而不是整台设备，因为这台设备其余的点位是在同一趟里读的。轮询间隔可以配置：设备的默认值（1000 毫秒）适用于每一个没有自己另作规定的点位。

## 点位寻址 {#tag-addressing}

点位的**路径**字段是相对于设备资源路径的那段 URL 路径：

| 字段 | 作用 | 取值 | 默认值 |
|---|---|---|---|
| 路径 | 为这个点位请求的那段路径。完整的 URL 是 `<transport>://<host>:<port>/<resource path>/<path>`。 | 自由文本（必填） | 空 |

例子：主机 `192.168.0.40` 降到明文 HTTP，资源路径 `api`，点位路径 `sensors/temp`，轮询的就是 `http://192.168.0.40/api/sensors/temp`。

## 读取 {#reads}

每一轮轮询都 GET 这个点位的 URL，并按点位声明的数据类型解析**整个响应体**：

| 类型 | 接受的响应体 |
|---|---|
| Float | 一个数字，固定区域性格式（`21.5`，小数点，不带千位分隔符） |
| Int32 | 一个整数（`42`） |
| Boolean | `true` 或 `false` |
| String | 什么都行；响应体原样就是那个值（一份 JSON 文档以它的原始文本到来） |

声明的类型解析不了的响应体，或者一个非成功的状态码，读作一次失败的读取：点位转为质量不可用，由它的读取失败策略决定呈现什么，见 [Connector](connector) 页面。非成功的状态是 endpoint 在拒绝这次读取，点位的原因会点名那个状态，并把 endpoint 随它说的话引出来（`HTTP 404 Not Found: …`），用的是和被拒绝的写入或命令一样的说法。声明的类型解析不了的响应体会给点位一个原因，引出没能读懂的内容，设备仍保持连接。一个完全不答的 endpoint 是设备的连接失败：设备会报告它并重新连接，它的点位会指向这台设备。点位红色那一行用工作站的语言说出这样的状态，401、403 和 404 还附上含义；解析不了的响应体则说成读不成点位类型之值的应答；endpoint 自己的原话留在事件页面。

## 写入 {#writes}

读写方式可写的点位用 **PUT** 写到同一个 URL：响应体是那个值的 JSON 形式，内容类型是 `application/json`。数字作为光秃秃的字面量发出去（`42.5`），布尔作为 `true` 或 `false`，文本则加引号（`"automatic"`）。endpoint 自己决定怎么处理它；非成功的状态就是 endpoint 在拒绝这个值：这次拒绝会点名那个状态，并把 endpoint 随它说的话引出来，用的是和被拒绝的命令一样的话，写入这个值的一方读得到原因。和别处一样，写入框接收的是工程值，原始值上总线之前会先把这个点位的转换环节反过来走一遍，见 [Connector](connector) 页面。

## 支持的数据类型 {#supported-data-types}

Boolean、Int32、Float 和 String。

## 命令 {#commands}

点位读一个值；命令则要求服务去做一件事。每一条命令都在设备上声明，位置是它页面上的**命令**卡片：一个名称、POST 过去的那条路径（接在设备自己的地址下面，和点位的路径完全一样），以及可选的、它所接收的那一个值的名字。行上的“运行”把它发出去并报告服务答了什么，而这条命令同时也成为这台设备在本工作站自己的 OPC UA 地址空间里的一个方法，所以任何能调用方法的东西都能下发它。你打进去的那个值原样作为请求体发出去。

服务答的什么，就是这条命令的结果。服务返回一个在成功范围之外的状态，那是服务在拒绝这条命令，不是连接失败：这次拒绝会点名那个状态，并把服务随它说的话引出来（“HTTP 500 Internal Server Error：燃烧器已闭锁”），这台设备上别的什么都不受它打扰。

## 设备发现 {#discovery}

这个驱动没有设备发现扫描。请按主机添加每一个 endpoint，按路径添加每一个值；添加设备的流程见 [Connector](connector) 页面。

## 现场设备访问 {#equipment-access}

使用自签名证书或由自建颁发机构签发证书的 HTTPS endpoint，会出示一份 Windows 中已安装的任何根证书都不为其担保的证书。无需在这台计算机上安装那个根证书。第一次连接会被拒绝，设备在树里和它的页面上显示**正在等待证书批准**，页面上的**查看证书**按钮会在那份证书上打开这张卡片；证书则在 HTTP 驱动页面末尾的**现场设备访问**里等你决定。这张卡片和 OPC UA 驱动页面上的是同一张。

| 分组 | 列出什么 | 你能做什么 |
|---|---|---|
| 等待批准 | 每一份被拒绝的证书，按它自称的名字列出：它的 SHA-256 指纹、遇到它的地址、最后一次尝试的时间和次数，以及详情（主体、颁发者、域名、有效期）。设备的**查看证书**打开的那一份会标为“已选中待审核”。 | **批准**从下一次连接尝试起接受这份证书。**阻止**继续拒绝它，且不再在这里列出。**丢弃所有待处理的证书**清空列表，什么也不批准、不阻止。 |
| 已批准的现场设备 | 你批准或导入的证书，连同谁在何时做的决定，以及每份证书最后一次被遇到的地址。 | **撤回批准**关闭连接，并把证书放回列表。**导入证书**在第一次连接之前批准一份你手头已有的公开证书文件（.der、.cer、.crt 或 .pem）。 |
| 被阻止的现场设备 | 你阻止的证书。被阻止的证书即使受 Windows 信任也会被拒绝。 | **解除阻止**把证书放回列表，但不批准它。 |

批准之前，请与管理该现场设备的人核对指纹。批准只接受这一份证书，而且只在它的有效期内；它代替 Windows 缺少的根证书和证书上写的名字，所以按 IP 地址连接的 endpoint，即使证书上写的是别的名字也能连上，而证书的其他方面一概不放宽。如果现场设备在你批准过证书的地址上换出另一份证书（证书续期等），读取就会停止，新证书在这里等待，工作站会带着**审核**按钮提示“证书已更换：`<名称>`”。Windows 已经信任的证书照旧被接受，永远不会出现在这里；没有任何东西会被自动批准。

驱动自己的失败会说明原因，而不是一个没有名字的 TLS 错误：“这台现场设备的证书（指纹的前 16 个字符）正在 HTTP 驱动页面的‘现场设备访问’里等待你的批准。批准之后就开始读取。”被阻止的则显示“……在本工作站已被阻止。请在 HTTP 驱动页面的‘现场设备访问’里审核它。”超出有效期、已吊销或签名损坏的证书会以这个原因被拒绝，且永远不会被列出，因为批准也不能让它变得可靠。

这些决定保存在工作站数据文件夹的 `ua\pki\http` 下，重启后依然有效。操作按钮只对能配置 Connector 的角色显示，而且只在工作站自己的窗口里生效：其他设备上的浏览器只能查看卡片、不能修改，也没有任何代理工具能批准证书（`connector_browse` 用 `awaitingCertificate` 标出正在等待的设备）。列表最多保留 100 份等待批准的证书；列表满了以后，新的证书仍会被拒绝但不会列出，卡片会说明这一点。
