Hurl Entry 详解:理解 Hurl 文件的最小执行单元与运行控制流 📅 发布时间:2026/9/13 1:34:32 👁 浏览次数: Hurl Entry 详解理解 Hurl 文件的最小执行单元与运行控制流【免费下载链接】hurlHurl, run and test HTTP requests with plain text.项目地址: https://gitcode.com/GitHub_Trending/hu/hurlHurl 以纯文本格式描述 HTTP 请求与断言而Entry条目是 Hurl 文件中最小的执行单元每个 Entry 由一个必选的 request 和可选的 response 组成。本文围绕 docs/entry.md 展开深入讲解 Entry 的定义、命令行选项与[Options]段的作用范围、Cookie 共享存储、重定向处理、重试机制以及skip/repeat/delay控制流并结合仓库源码说明每个机制在 runner 中的实际执行路径帮助你写出可预测、可调试、可复用的 Hurl 场景文件。Entry 的定义与文件结构Hurl 文件就是一个 Entry 列表每个 Entry 由一个必选的 request以及一个可选的 response 组成。response 不是必需的——只包含请求序列的 Hurl 文件完全合法。加入 response 的目的主要有两个捕获值capture values从响应中提取变量供后续请求使用参见 capturing-response.md对 HTTP 响应添加断言asserts校验状态码、响应头、响应体等参见 asserting-response.md。一个典型的多 Entry 文件示例# 首先测试首页标题。 GET https://acmecorp.net HTTP 200 [Asserts] xpath normalize-space(//head/title) Hello world! # 获取一些新闻response 描述是可选的 GET https://acmecorp.net/news # 发送一个不带 CSRF token 的 POST 请求 # 并检查状态码为 Forbidden 403 POST https://acmecorp.net/contact [Form] default: false email: john.doerookie.org number: 33611223344 HTTP 403这个例子展示了三种形态带断言和响应校验的 Entry、仅发请求不带响应的 Entry以及带请求体[Form]段并校验状态码的 Entry。response 出现时其内部结构为HTTP 版本与状态码必填→ 可选响应头 → 可选的[Captures]/[Asserts]段二者无序→ 可选响应体详见 response.md 的结构示意。Entry 的粒度请求 响应 一个可独立执行的步骤从仓库源码看Hurl 的核心运行器对每个 Entry 独立执行packages/hurl/src/runner/entry.rs 中的run函数接收单个Entry、当前索引、HTTP 客户端、变量集与全局运行选项返回一个EntryResult。而 packages/hurl/src/runner/hurl_file.rs 的主循环逐个取出 Entry先计算该 Entry 生效的选项再决定跳过、延时、执行或重试。也就是说Entry 是选项计算 → 控制流判断 → HTTP 执行 → 断言/捕获 → 结果收集这一完整链路的最小单位。Options 的作用范围全局命令行 vs 局部[Options]段命令行上指定的 Options 会作用于 Hurl 文件中的每一个 Entry。例如--location会让文件中每个 Entry 都跟随重定向$ hurl --location foo.hurl而使用[Options]段可以把某个选项只作用于指定的某个请求。下面的例子中只有第二个 Entry 会跟随重定向因此能断言 200 而不是 301第一个和第三个 Entry 保持默认行为GET https://google.fr HTTP 301 GET https://google.fr [Options] location: true HTTP 200 GET https://google.fr HTTP 301[Options]段也常用于只对某个特定 Entry 开启日志输出方便定位问题# ... 之前的条目 GET https://api.example.org [Options] very-verbose: true HTTP 200 # ... 之后的条目[Options]段支持的选项非常丰富包括compressed、connect-timeout、delay、http3、insecure、ipv6、limit-rate、location、max-redirs、max-time、output、retry、retry-interval、skip、user、proxy、variable、verbose、very-verbose等完整清单与注释参见 docs/request.md。需要注意的一个例外在[Options]段中定义的变量包括通过variables-file加载的变量也会作用于后续 Entry这是所有选项中唯一突破仅当前请求作用域的详见 docs/request.md。源码视角局部选项如何合并进全局选项在 packages/hurl/src/runner/options.rs 等代码中[Options]段的每个OptionKind都会先求值例如Delay选项通过eval_duration_option把 300ms 解析为Duration再写入entry_options。随后 packages/hurl/src/runner/hurl_file.rs 调用options::get_entry_options(entry, runner_options, ...)将命令行全局选项与 Entry 局部选项合并得到该 Entry 实际生效的完整选项集。这也是为什么--location foo.hurl与局部location: true可以并存、互不干扰。Cookie 存储同文件内共享的会话级状态默认情况下同一个 Hurl 文件内的请求共享 Cookie 存储因此可以写出依赖登录态或会话 Cookie 的连续场景。若需要隔离可用--no-cookie-store选项禁用 Cookie 引擎参见 docs/manual.md。# 正常共享 Cookie 存储 $ hurl session.hurl # 禁用 Cookie 存储 $ hurl --no-cookie-store session.hurl源码层面packages/hurl/src/runner/runner_options.rs 中use_cookie_store的默认值为true对应--no-cookie-store的置位逻辑见 packages/hurl/src/runner/runner_options.rs。在 packages/hurl/src/http/client.rs 中只有当options.use_cookie_store为真时才会向 libcurl 注册 Cookie 引擎这正是同文件共享 Cookie、跨文件隔离的实现基础。跨多次运行持久化 Cookie 可用-b/--cookie与-c/--cookie-jar读写 Netscape 格式 Cookie 文件参见 docs/manual.md。Redirects 重定向逐级断言 vs 自动跟随默认情况下Hurl 不自动跟随重定向。因此要真正跑完一次重定向可以用多个 Entry 逐级描述每一步并在每一级响应上插入断言# 第一个 Entry测试重定向状态码与 Location 头 GET https://example.org HTTP 301 Location: https://www.example.org # 第二个 Entry200 OK 响应 GET https://www.example.org HTTP 200或者使用--location/--location-trusted选项强制跟随重定向。此时断言作用在最后收到的响应上还可通过--max-redirs限制重定向次数默认上限 50设为-1表示不限制参见 docs/manual.md# 运行方式hurl --location foo.hurl GET https://example.org HTTP 200也可以只对某个特定请求强制跟随重定向GET https://example.org [Options] location-trusted: true HTTP 200两种重定向测试思路方式一逐步执行并断言每一级重定向——每个 Entry 对应一跳精确控制GET https://example.org/step1 HTTP 301 [Asserts] header Location https://example.org/step2 GET https://example.org/step2 HTTP 301 [Asserts] header Location https://example.org/step3 GET https://example.org/step3 HTTP 200方式二使用--location/--location-trusted自动跟随再用redirects查询逐级校验redirects查询返回重定向集合可用count、nth与location过滤器测试参见 asserting-response.mdGET https://example.org/step1 [Options] location: true HTTP 200 [Asserts] redirects count 2 redirects nth 0 location https://example.org/step2 redirects nth 1 location https://example.org/step3url查询则直接返回最终生效的 URLGET https://example.org/step1 [Options] location: true HTTP 200 [Asserts] url https://example.org/step3源码视角跟随重定向时的凭据与安全性自动跟随重定向实现在 packages/hurl/src/http/client.rs 的execute_with_redirect它在calls列表里保留从第一步到最后一跳的每一次请求/响应这正是redirects查询与时间线报告的数据来源。在 packages/hurl/src/http/client.rs 中跟随重定向时若主机名发生变化会过滤Authorization与Cookie头除非使用--location-trusted显式信任跳转后的主机CredentialForwarding::AllHosts见 packages/hurl/src/runner/options.rs凭据是否被过滤由should_strip_credentials_on_redirect依据 scheme、host、port 是否变化判定相关单测见 packages/hurl/src/http/client.rs。此外当重定向导致方法变化时如 301 后 POST 变为 GET请求体会被丢弃方法转换逻辑见 packages/hurl/src/http/client.rs。Retry 重试轮询场景与不稳定环境的利器每个 Entry 都可以在断言、捕获或运行时错误发生时被重试。重试让轮询直到完成这类场景变得很自然也让脚本在抖动环境下更稳定。需要指出这里的错误既包括显式的[Asserts]段断言也包括隐式断言如响应头或状态码。重试可以全局设置--retry与--retry-interval参见 docs/manual.md也可以在某个请求上用[Options]段局部开启# 全局最多重试 3 次每次间隔 500ms $ hurl --retry 3 --retry-interval 500ms poll.hurl下面这个例子演示了典型的创建任务 → 轮询直到完成# 创建新任务 POST http://api.example.org/jobs HTTP 201 [Captures] job_id: jsonpath $.id [Asserts] jsonpath $.state RUNNING # 轮询任务状态直到完成 GET http://api.example.org/jobs/{{job_id}} [Options] retry: 10 # 最大重试次数-1 表示不限制 retry-interval: 300ms HTTP 200 [Asserts] jsonpath $.state COMPLETED要点说明retry的取值0表示不重试默认正整数表示最大重试次数-1表示无限重试retry-interval是每次重试之间的间隔默认1000ms支持ms、s、m、h等单位只有HTTP 执行类错误参与重试计算 Entry 选项时的错误、输出写入错误不计入重试。源码视角重试的执行循环在 packages/hurl/src/runner/hurl_file.rs 的run_entry中重试逻辑是一个循环每轮先执行entry::run若存在错误且options.retry.is_some()、未达到重试上限就记录日志、按retry_interval睡眠然后进入下一轮达到上限则打印 Retry max count reached, no more retry。其中retry_count rCount::Finite(r)即判定重试次数耗尽见 packages/hurl/src/runner/hurl_file.rs。全局默认的retry_interval为 1000ms定义在 packages/hurl/src/runner/runner_options.rs。注意--delay只作用于首次请求重试请求之间的间隔由retry-interval控制二者语义不同参见 docs/manual.md。Control flow 控制流skip、repeat 与 delay在[Options]段中可以使用skip和repeat控制执行流程skip: true/false跳过当前请求无条件执行下一个请求repeat: N将请求循环执行 N 次。若期间出现断言或运行时错误执行会停止。# 该请求将恰好执行 3 次 GET https://example.org/foo [Options] repeat: 3 HTTP 200 # 该请求被跳过 GET https://example.org/foo [Options] skip: true HTTP 200此外可以在请求之间插入delay在执行某请求之前先等待一段时间即 sleep# 延迟 5 秒后执行的请求 GET https://example.org/foo [Options] delay: 5s HTTP 200delay与repeat也可以作为命令行选项全局生效$ hurl --delay 500ms --repeat 3 foo.hurl说明--delay是每个请求执行前的睡眠时间但不作用于因--retry触发的重试请求--repeat则是把输入文件序列整体重复 N 次-1表示无限循环例如以 a.hurl、b.hurl、c.hurl 为输入时repeat 2 的执行顺序为 a、b、c、a、b、c参见 docs/manual.md 与 docs/manual.md。源码视角skip / repeat / delay 在运行器中的实现在 packages/hurl/src/runner/hurl_file.rs 的主循环中三个控制流按顺序处理skipoptions.skip为真时打印 Entry has been skipped 并直接进入下一个 Entryrepeat 0repeat: 0等价于跳过Count::Finite(0)delaydelay_ms 0时打印延迟日志并thread::sleep(delay)。随后在 packages/hurl/src/runner/hurl_file.rs 通过repeat_count计数器判断当前 Entry 是否达到repeat次数达到则重置计数器并进入下一 Entry否则在当前 Entry 上循环执行。完整的 Entry 执行周期图下图概括了每个 Entry 从加载到收尾的完整执行周期含 skip、delay、执行、断言/捕获、重试与 repeat 判定是理解上述所有机制的汇总参考实战建议明确 Entry 粒度把一个请求 它要校验的响应当作一个 Entry 来组织文件响应可选但需要捕获或断言时不要省略。优先用[Options]段做局部行为全局命令行选项影响所有 Entry只有个别请求需要跟随重定向、加长超时或开启详细日志时用[Options]段局部控制避免污染整文件。重定向二选一需要严格校验每一跳状态码、Location头时逐级写 Entry只需要最终结果时用--location/--location-trusted配合redirects、url查询断言。轮询用 retry 而不是手写循环retryretry-interval能自然表达等待任务完成配合[Captures]捕获的job_id做模板变量代码简洁且可读。控制流保持克制repeat、skip、delay适用于采样、幂等重放与节奏控制但过度使用会降低脚本可读性保持每个 Entry 意图单一。相关文档与源码索引本主题主文档docs/entry.md请求与响应docs/request.md、docs/response.md捕获与断言docs/capturing-response.md、docs/asserting-response.md命令行选项总表docs/manual.md运行器主循环packages/hurl/src/runner/hurl_file.rsEntry 执行与重试packages/hurl/src/runner/hurl_file.rs、packages/hurl/src/runner/entry.rs选项解析与合并packages/hurl/src/runner/options.rs、packages/hurl/src/runner/runner_options.rs重定向与 Cookie 实现packages/hurl/src/http/client.rs、packages/hurl/src/http/client.rs集成测试示例integration/hurl/tests_ok/parallel、integration/hurl/tests_ok/retry【免费下载链接】hurlHurl, run and test HTTP requests with plain text.项目地址: https://gitcode.com/GitHub_Trending/hu/hurl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考