实验中的数据
值在一次运行中流动:一个参数选择目标,一个响应的字段成为下一个请求的标头,一个生成的 id 随命令发出又在检查中返回。本页介绍这些值来自哪里,以及字段如何使用它们。
| 来源 | 写法 | 在哪里设置 |
|---|---|---|
| 参数 | {{api}} 或 {{params.api}} | 参数 面板、配置、自定义运行… |
| 变量 | {{token}} 或 {{vars.token}} | 运行中的某个节点:提取值、等待节点、发送并等待回复的节点 |
| 机密 | {{secret.API_TOKEN}} | 计算机的凭据存储,或服务器的环境变量和文件 |
| 内置值 | {{run.seed}}、{{now.iso}}、{{counter}} | 运行本身 |
| 生成器 | {{uuid}}、{{random_int(1, 100)}} | 从本次运行的种子中抽取 |
参数
参数是一个具名文本值,任何模板字段都可以使用它。把目标放进参数里,这样更改地址只需改一处,而不是每个节点各改一次。
添加参数
- 在编辑器工具栏中按 参数(
{ })。 - 在 默认值 标签页上,按 添加参数。
- 输入 名称 和 值,例如
api和http://127.0.0.1:8080。 - 在某个节点的字段中,写出
{{api}}/login。
面板中的每次更改都是对实验的一次编辑:它会随实验一起保存,也能像其他编辑一样用 Ctrl+Z 撤销。
规则
| 规则 | 限制 |
|---|---|
| 名称 | 以字母或 _ 开头,之后是字母、数字和 _ |
| 保留名称 | vars、params、secret、run、node、now、uuid、counter、random_int、random_float、pick |
| 每个实验的参数 | 64 |
| 单个值的大小 | 64 KiB |
| 名称 | 唯一;变量不能与参数同名 |
值就是纯文本,按原样插入:值内部的 {{…}} 不会被解析。当某个字段要求参数的一部分 ({{config.ports[0]}})时,该值会按 JSON 读取;不是 JSON 的值没有部分。
名称无效、为保留名或重复的参数不会阻止实验保存,因此您可以继续输入;在名称修正之前,实验不会运行。
配置
配置是一组具名的参数值——笔记本、舞台、场馆——因此切换目标是一种选择,而不是逐个编辑节点。配置更改部分参数;其余参数保持默认值。
创建配置
- 打开 参数 并按 配置。会打开一个新标签页。
- 在 配置名称 中重命名它。
- 对配置更改的每个参数,输入其值。留空的字段保持 默认值,字段中会以灰色显示;使用默认值(↺)会清除 一个值。
- 按 用于运行 用它来运行。使用中的配置标签页带有 ● 使用中。在 默认值 标签页上按 用于运行 会回到默认值。
实验有了配置后,工具栏中的 配置 列表可在它们之间切换。运行、预览和 立即发送 都使用使用中的配置,它保存在实验中,因此导出的文件打开后具有相同的目标。删除配置 会删除屏幕上显示的配置。
| 规则 | 限制 |
|---|---|
| 每个实验的配置 | 32 |
| 名称 | 1–64 个字符,唯一(首尾空格不计) |
| 值 | 只能是已存在的参数;最多 64 个 |
重命名或删除参数会同时更改每个配置中的它。
一次运行使用哪个值
后者生效:
- 参数的默认值,在 默认值 标签页上;
- 使用中的配置的值(如果它设置了该值);
- 在 自定义运行… 中仅为本次运行输入的值—— 参见使用其他值运行。
自定义运行… 只能设置实验已有的参数。运行报告 会记录所用的配置、为本次运行输入的值以及它使用的每一个值。
无法运行的配置
每次检查实验时,其他配置和默认值也会被检查。某个会失败的配置——比如一个不是 http:// 或 https:// 的 URL——会在标签页和工具栏列表中带有 ⚠,其工具提示会说明原因。它不会阻止使用其他配置的运行。
模板
{{ }} 内的文本是一个表达式;字段中的其他一切都会按原样保留。
{{api}}/users/{{user.id}}?trace={{uuid}}
Bearer {{secret.API_TOKEN}}- 花括号内的空格无关紧要:
{{ token }}就是{{token}}。 \{{写出一个字面量{{。- 单独的
}}是纯文本。 - 值按原样插入,不带引号。在 JSON 正文中,引号请自行书写:
"id": "{{uuid}}"。
名称
| 表达式 | 值 |
|---|---|
{{name}} | 如果这条路径上设置了变量 name,则为该变量,否则为参数 name |
{{vars.name}} | 仅变量 |
{{params.name}} | 仅参数 |
{{secret.NAME}} | 已存储的机密 NAME——参见机密 |
{{name.field}} | JSON 值的一个字段 |
{{name[0]}} | JSON 数组的一个元素 |
{{name["a b"]}}、{{name['a b']}} | 名称含其他字符的字段 |
. 之后的字段名可以包含字母、数字、_ 和 -。可以连续使用: {{reply.args[0]}}、{{order.items[2].sku}}。
值的写法
| 值 | 写法 |
|---|---|
| 文本 | 文本本身 |
| 数字 | 其最短形式:42、0.5 |
true、false | true、false |
null | null |
| 对象、数组 | 紧凑 JSON:["x","y"] |
内置值
| 表达式 | 值 |
|---|---|
{{run.id}} | 本次运行的任务编号;在预览和 立即发送 中为 0 |
{{run.seed}} | 本次运行的种子 |
{{node.id}} | 正在执行的节点的 id |
{{now}} | 当前时间,Unix 毫秒 |
{{now.iso}} | 当前 UTC 时间,ISO 8601,带毫秒:2026-09-30T12:34:56.789Z |
{{counter}} | 此节点在本次运行中运行了多少次,包括本次,从 1 开始 |
{{counter}} 按节点计数:在循环的循环体中它是 迭代的编号,在重复的节点中它是发送的编号。 run、node 和 now 只有列出的字段;其他任何内容都是错误。
生成器
| 表达式 | 值 |
|---|---|
{{uuid}} 或 {{uuid()}} | 一个版本 4 UUID |
{{random_int(min, max)}} | 从 min 到 max 的整数,两端都包含;参数为整数,min ≤ max |
{{random_float(min, max)}} | 从 min 到(但不包括)max 的数,带 3 位小数;min < max |
{{random_float(min, max, digits)}} | 同上,带 digits 位小数,0–9 |
{{pick(a, b, c)}} | 参数之一,至少一个 |
参数用逗号分隔。带引号的参数("dark blue" 或 'a, b') 可以包含除自身引号外的任何内容;不带引号的参数可以包含字母、 数字和 _ - . : / +。空参数是错误。
每个生成器都从本次运行的种子中抽取。一个节点的一次执行所得到的值 只取决于种子、节点的 id 以及该节点已运行了多少次,因此并行分支绝不会 改变彼此的值,相同的种子会再次生成相同的值。一个节点内的抽取 遵循其字段的顺序。{{now}} 和 {{run.id}} 不可重现。参见 种子。
建议
在模板字段中输入 {{,或按 Ctrl+Space, 会打开一个分四组的列表:参数(带其值)、 变量(在此节点上游设置的,带设置它们的节点 (回复的字段也是,例如 reply.args[0]))、机密 和 生成器。↑ 和 ↓ 选择, Enter 或 Tab 插入,Esc 关闭列表并 保留字段内容。
未知名称是错误
没有值的名称绝不会变成空字符串。运行之前,字段使用的每个 名称都必须是参数、有效的机密名称,或者在通往该节点的每一条路径上都设置了变量。编辑器会指出节点和 字段:
| 问题 | 运行之前 | 运行期间 |
|---|---|---|
| 没有人设置的名称 | name.unknown | — |
| 只在一部分路径上设置的变量 | name.not_on_every_path | — |
{{params.x}} 却没有参数 x | param.unknown | — |
| 值不具有的字段 | — | template.no_field |
未闭合的 {{、空的 {{}}、格式错误的参数 | template.*,带位置 | — |
这些代码的文本见错误。
哪些字段接受模板
| 节点 | 模板字段 |
|---|---|
| HTTP 请求 | URL、标头名称和值、正文、Basic 和 Digest 的用户名和密码、Bearer 令牌 |
| OSC 消息 | 目标、地址、文本参数;带回复时:其地址模式和规则值 |
| UDP 数据报 | 目标、载荷;带回复时:其模式 |
| TCP 消息 | 主机、载荷 |
| MQTT 发布 | 代理主机、主题、载荷 |
| 日志标记 | 消息 |
| 响应文本 | 预期文本 |
| 响应标头 | 标头名称、预期文本 |
| 检查值、按值分支、循环 的退出条件 | 值、预期值 |
| 等待 OSC | 地址模式、规则值 |
| 等待 UDP、等待 WebSocket | 模式 |
| 等待 MQTT | 代理和主题(仅参数)、模式 |
| 等待 HTTP 请求 | 路径模式、条件 |
| 网络损伤 | 监听和目标(仅参数) |
| WebSocket 连接 | URL、标头名称和值 |
| WebSocket 发送 | 载荷 |
| WebSocket 关闭 | 原因 |
数字——端口、超时、延时、状态码、带类型的 OSC 数字——以及等待节点的 监听地址都是字面量。模拟器 用收到的内容 ({{request.…}})和参数来渲染自己的回复;参见 故障。
仅参数。 有些字段在第一个步骤之前就已打开,此时还没有 变量存在:等待 MQTT 的代理和主题、一个 网络损伤 的监听和目标。它们只接受文本和参数, 没有别的(node.params_only)。
像字面量一样检查。 只使用参数的字段会在运行前解析,并按 本次运行将发送的文本进行检查:URL 必须是 http:// 或 https://,OSC 目标为 IP:port 或 host:port,标头名称有效。带 变量或生成器的字段在运行时检查。
预览
当选中的节点带有模板时,其属性会显示它在已知当前值的情况下将会做什么:发送为 将发送, 等待为 将等待,比较为 将比较。 引擎会解析它,使用的代码与运行完全相同,因此预览绝不会与运行不一致。
- 参数来自使用中的配置。
- 变量来自编辑器在此会话中见过的内容:上次运行的步骤, 以及 立即发送。
- 已存储的机密显示为
••••。 - 尚无值的名称按原样保留,预览会列出它。未存储的 机密会单独列出。
- 生成器使用实验固定的种子,未固定时使用
0,作为 节点的首次执行。固定了种子时,预览会显示节点在运行中首次执行 将发送的生成值。
提取值
提取值 读取其路径上最近一次 HTTP 响应中的一个值, 并把它写入变量。
| 字段 | 内容 |
|---|---|
| 变量 | 要写入的变量;适用参数的命名规则 |
| 提取自 | 值来自哪里(见下文) |
| JSON 路径、标头名称 或 模式(有分组时取第 1 组) | 取决于来源,要读取的内容 |
| 提取自 | 读取 | 值 |
|---|---|---|
| JSON 字段 | 按路径读取作为 JSON 的正文 | JSON 值:文本、数字、对象、数组 |
| 标头 | 该名称的第一个标头,不区分大小写 | 文本 |
| 状态码 | 状态码 | 数字 |
| 整个正文 | 整个正文 | 文本 |
| 正则表达式 | 正文中的第一个匹配 | 如果模式有分组,则为第 1 个捕获组,否则为整个匹配 |
JSON 路径。 $.token、$.items[0].id、$["a b"]、$['a b']['c-d']; 开头的 $. 可以省略(token、items[0].id),单独的 $ 表示 整个正文。
正则表达式使用 Rust regex 引擎的语法,它没有 环视,也没有反向引用。匹配会在正文中任意位置搜索;需要时 用 ^ 和 $ 锚定。
在下列情况下,步骤会失败并指出缺少什么:
- 在这条路径上它之前没有 HTTP 请求运行过(
check.no_response;编辑器 在无法成立的图中已经拒绝,graph.needs_http); - 正文不是 JSON,或者路径不在其中;
- 标头不存在,或者模式不匹配;
- 对于 JSON 路径或整个正文,正文超过响应保留的 256 KiB; 或者对于模式,在保留的部分中没有任何匹配 (
extract.truncated)。
时间线会显示写入的值:token = abc123。
点击即可提取
在 HTTP 请求 上使用 立即发送 会显示其 JSON 响应。点击其中的一个 值:请求之后会添加一个 提取值 节点,路径已填好,名称取自该键,该值会立即 为预览所知。
变量
变量保存一个 JSON 值。以下节点会写入变量:
| 节点 | 写入 | 在哪个输出上 |
|---|---|---|
| 提取值 | 提取的值 | 其输出 |
| 等待 OSC、等待 UDP、等待 MQTT、等待 HTTP 请求、等待 WebSocket | 到达的内容,默认名 reply(HTTP 为 request) | 仅 已匹配 |
| OSC 消息、UDP 数据报 带 等待回复 | 回复,默认名 reply | 其输出 |
等待节点写入的是一个对象;之后的字段读取它的部分:
| 等待 | 字段 |
|---|---|
| OSC | address、args、from、ms |
| UDP | text、hex、bytes、from、ms,以及带模式时的 match |
| MQTT | topic,以及 UDP 的字段 |
| WebSocket | UDP 的字段,消息为 JSON 时还有 json |
| HTTP 请求 | method、path、query、headers、body、json、params、from、ms |
ms 是从分支上最近一次动作到到达的时间。确切内容见节点参考。
变量在哪里可见
变量从写入它的那个输出起存在,在经过该输出的路径上存在:
- 在可选路径合并之后——分支的 是 和 否 再次汇合——只有每一条路径都设置的值才是已知的。
- 在 汇合分支 之后,任何汇入它的分支任意一个 设置的值都是已知的:它们全都运行过。
- 在 循环 的 完成 或 上限 之后,以及在其退出条件中,循环体的每次迭代都设置的值是已知的。
- 等待节点的变量在其 超时 输出之后不再已知。
每个并行分支都在自己的变量副本上工作。Join 按传入接线的顺序合并这些 副本,两条都设置了同名值时后面的接线胜出,因此结果绝不取决于 哪个分支先完成。参见 运行如何流动。
比较值
检查值 在比较不成立时使运行失败; 按值分支 从 是 或 否 离开; 一个 循环 使用同样的比较作为其退出条件。每个都有 值、条件 和 预期值 值,两段 文本都是模板:
| 值 | 条件 | 预期值 |
|---|---|---|
{{status}} | 小于 | 300 |
{{reply.args[0]}} | 等于 | {{nonce}} |
| 条件 | 成立条件 |
|---|---|
| 等于、不等于 | 两者相等(不相等)——都为数字时按数字比较(200 等于 200.0),否则按精确文本比较,区分大小写 |
| 小于、不大于、大于、不小于 | 按数字比较;某一侧不是数字时步骤失败(compare.not_numbers),而不是安静地给出否 |
| 包含 | 值包含预期文本,区分大小写 |
| 匹配正则 | 预期值中的正则表达式在值中任意位置匹配 |
| 为空、不为空 | 去除空格后值为空,或不为空;不使用预期值 |
数字是去除空格后能读作数字的文本:42、-1.5、 1e3。时间线会显示实际进行的比较,401 = 200,每一侧截断 到 120 个字符。
机密
令牌或密码以 {{secret.NAME}} 的形式放入字段。实验 文件只保留名称;值留在它被存储的地方,绝不 进入界面。
机密存放在哪里
| Signal Lab 运行在哪里 | 存储 | 从界面 |
|---|---|---|
| Windows 桌面应用 | Windows 凭据管理器,服务名 SignalLab 下,每个名称一条 | 设置、替换、移除 |
| Linux 桌面应用 | 无:需要机密的运行会以 secret.unsupported 失败 | — |
| 服务器 | 环境变量 SIGNALLAB_SECRET_<NAME>,否则是其机密文件夹中的文件 <NAME>,默认 /run/secrets/signallab,除非另有设置 | 只读 |
命令行 signallab | 像服务器一样,或者用 --secrets system 使用 Windows 凭据管理器 | — |
机密 部分的标题带有一个工具提示,说明您所在的位置适用于其中哪一种: Windows 存储、服务器的环境变量和 文件,或者——在 Linux 桌面应用中——没有存储。在那里, secret.unsupported 说明机密保存在 Windows 凭据 管理器中,而该系统没有它。
机密属于计算机或服务器,而不属于某一个实验:使用 {{secret.API_TOKEN}} 的两个实验使用同一个值。
在服务器上,环境变量优先于文件。文件末尾的 换行不算值的一部分,空文件视为无机密。服务器的 文件夹用 --secrets-dir 或 SIGNALLAB_SECRETS_DIR 设置; 参见服务器。命令行见 signallab run。
| 规则 | 限制 |
|---|---|
| 名称 | 以字母或 _ 开头,之后是字母、数字和 _;最多 128 个字符 |
| 值 | 非空,最多 16 KiB |
设置机密
在 Windows 上:
- 打开 参数。机密 部分列出实验的字段 使用的每一个机密,每个都标有 已存储 或 此计算机上未设置。
- 按名称旁边的 设置…,或对尚无字段使用的名称按 机密。
- 输入值——字段显示为圆点——然后按 保存 或 Enter。字段会被清空;任何东西都无法再读回该值。
替换… 存储一个新值,移除 从凭据存储中删除它。在此会话中存储过的名称也会出现在建议中。
在连接到服务器的浏览器中,该部分只会显示 已在服务器上设置 或 服务器上未设置:在服务器运行的地方设置值,有两种方式:
# in the server's environment
SIGNALLAB_SECRET_API_TOKEN='…'
# or as a file in its secrets folder
printf '%s' '…' > /run/secrets/signallab/API_TOKEN文件每次运行开始时都会读取,因此更改过的文件从下一次运行起生效;更改过的环境变量需要重启服务器。
运行之前
本次运行的字段使用的每一个机密都必须已存储。缺少的机密会在任何流量之前、 在第一个使用它的节点和字段处停止运行 (secret.missing)。立即发送 对其节点做同样的检查。
遮蔽
当一次运行或一次 立即发送 使用机密时,它们值的每次出现 都会在离开引擎的一切内容中被替换为 ••••:
- 步骤文本、错误,以及步骤写入的变量;
- 运行报告;
- 立即发送 的结果,包括它显示的 HTTP 响应;
- 检查器 的帧,在运行持续期间捕获的——在十六进制 转储中,值的每个字节变成
*,因此偏移量保持正确。
Basic 认证以 base64 发送 name:password;当其中任一部分包含 机密时,那段 base64 文本也会被遮蔽。流量本身携带真实 值。预览将已存储的机密显示为 ••••。一个 模拟器 的回复不能使用机密。
命令
预览是 experiment_resolve; 机密用 secret_status、 secret_set 和 secret_delete 列出、设置和移除。没有任何命令会返回 机密的值。