策略片段的变量管理

适用于:所有 API 管理层级

上下文变量 支持在高级管道场景中,策略片段之间的数据共享。 适当的变量管理对于生成性能最佳的可靠管道至关重要。 不当处理可能会导致运行时错误、性能问题和不可预知的行为。

变量基础知识

上下文变量提供策略片段之间的线程安全数据共享,并使用内置的 集变量 策略创建。 每个请求都维护自己的独立变量上下文,确保并发请求不会相互干扰。

变量生命周期管理

  • 请求范围:变量仅在单个请求期间存在,并在请求完成时自动进行垃圾回收。

  • 阶段持久性:入站阶段中设置的变量在整个后端、出站和错误阶段在同一请求中保持可用。

  • 线程隔离:严格线程隔离可确保每个请求使用自己的上下文对象在其自己的线程上运行,从而防止跨请求数据干扰。

  • 顺序更新:任何片段都可以修改现有变量,后续片段覆盖以前的值。 顺序执行消除了锁定机制的需求。

  • 存储阈值:平台优化小型集合的上下文变量管理,通常每个请求 50 个变量或更少。

在片段中设置和检索变量

<!-- Example: Set a request-id context variable that is a required value for other fragments -->
<set-variable name="request-id" value="@{
    var requestId = context.Request.Headers.GetValueOrDefault("X-Request-ID", "");
    if (string.IsNullOrEmpty(requestId)) {
        return Guid.NewGuid().ToString();
    }
    return requestId;
}" />

<!-- Example: Retrieve the same request-id context variable safely in another fragment -->
<set-header name="X-Correlation-ID" value="@{
    return context.Variables.GetValueOrDefault<string>("request-id", "unknown");
}" />

最佳做法

使用安全的方式访问变量

请始终谨慎对待潜在的 null 值,使用GetValueOrDefault进行安全访问,并为所有变量访问提供有意义的默认值。

<!-- Safe access with default value -->
<set-variable name="log-level" value="@{
    return context.Variables.GetValueOrDefault<string>("config-log-level", "INFO");
}" />

<!-- Safe string interpolation using GetValueOrDefault -->
<set-variable name="cache-key" value="@{
    var userId = context.Variables.GetValueOrDefault<string>("auth-user-id", "anon");
    var resource = context.Variables.GetValueOrDefault<string>("request-resource", "default");
    
    return $"cache:{userId}:{resource}";
}" />

检查变量是否存在

在访问这些变量之前,请确保先决条件片段创建的变量存在。 缺少依赖项时,请从两种策略中进行选择:

策略 1: 快速失败(关键依赖项)

缺少关键依赖项时返回错误响应:

<choose>
    <when condition="@(!context.Variables.ContainsKey("user-id"))">
        <!-- Critical dependency missing - fail immediately -->
        <return-response>
            <set-status code="500" reason="Internal Server Error" />
            <set-body>{"error": "Required variable missing", "missing_dependency": "user-id"}</set-body>
        </return-response>
    </when>
    <otherwise>
        <!-- Safe to proceed - use the user-id variable -->
        <set-header name="X-User-ID" exists-action="override">
            <value>@(context.Variables.GetValueOrDefault<string>("user-id", ""))</value>
        </set-header>
    </otherwise>
</choose>

策略 2: 妥善处理(可选依赖项)

如果缺少可选依赖项,请继续执行适当的回退行为:

<choose>
    <when condition="@(context.Variables.ContainsKey("user-id"))">
        <!-- Optional variable available - use it -->
        <set-header name="X-User-ID" exists-action="override">
            <value>@(context.Variables.GetValueOrDefault<string>("user-id", ""))</value>
        </set-header>
    </when>
    <otherwise>
        <!-- Fallback to default when variable unavailable -->
        <set-header name="X-User-ID" exists-action="override">
            <value>unknown</value>
        </set-header>
    </otherwise>
</choose>

最小化变量访问

通过将多个访问合并到单个表达式中来减少上下文变量查找:

<!-- Good: Single consolidated access -->
<set-variable name="log-entry" value="@{
    var level = context.Variables.GetValueOrDefault<string>("log-level", "INFO");
    var requestId = context.Variables.GetValueOrDefault<string>("request-id", "unknown");
    return $"[{level}] Request {requestId} completed";
}" />

<!-- Avoid: Multiple separate accesses -->
<set-variable name="level-prefix" value="@("[" + context.Variables.GetValueOrDefault<string>("log-level", "INFO") + "]")" />
<set-variable name="request-suffix" value="@("Request " + context.Variables.GetValueOrDefault<string>("request-id", "unknown") + " completed")" />
<set-variable name="log-entry" value="@(context.Variables.GetValueOrDefault<string>("level-prefix", "") + " " + context.Variables.GetValueOrDefault<string>("request-suffix", ""))" />

维护一致类型

使用显式类型处理实现最佳性能和可靠性。 使用 策略表达式时,使用运算符指定预期类型 @()

<!-- Set as boolean, use as boolean -->
<set-variable name="should-log-debug" value="@(true)" />
<choose>
    <when condition="@(context.Variables.GetValueOrDefault<bool>("should-log-debug", false))">
        <!-- Include detailed debug information in logs -->
    </when>
</choose>