如何重用 Azure API 管理策略中的响应上下文变量?

And*_*art 4 c# azure-api-management ibm-api-management apim

我正在利用 Azure API 管理解决方案编写概念验证。

我正在尝试编写一项<inbound>执行以下操作的策略:

  • 用于<send-request>向 API 的身份验证端点发出请求。
  • 身份验证 API 返回两个密钥,必须将其作为 http 标头包含在内,以便能够向其他端点发出后续请求。
  • 我正在将身份验证 API 的响应解析为 json 使用JObject
  • 然后我尝试从 json 对象的两个属性中读取值(它们是字符串)
  • 然后,我将向不同的 API 端点发出后续请求,并设置两个 http 标头。标头的值必须是第一个(身份验证)响应中的两个变量。

这就是我目前的政策:

<inbound>
  <base />

  <!-- Authenticate with the API and get authentication tokens for subsequent calls -->
  <send-request mode="new" response-variable-name="auth" timeout="20" ignore-error="true">
    <set-url>https://www.service.com/api/authenticate</set-url>
    <set-method>POST</set-method>
    <set-header name="Content-Type" exists-action="override">
      <value>application/json</value>
    </set-header>
    <set-body>
      @{
        var credentials = new JObject(); 

        credentials.Add(new JProperty("logonId", "{{API_LOGON_USERNAME}}")); 
        credentials.Add(new JProperty("logonPassword", "{{API_LOGON_PASSWORD}}")); 

        return credentials.ToString(); 
      }
    </set-body>
  </send-request>

  <!-- Make second query to a different endpoint, using the authentication tokens as http headers -->
  <send-request mode="new" response-variable-name="data" timeout="20" ignore-error="true">
    <set-url>https://www.service.com/api/data</set-url>
    <set-method>GET</set-method>
    <set-header name="TokenA" exists-action="override">
      <value>
        @{
          JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>(); 
          return identity.SelectToken("TokenA").ToString(); 
        }
      </value>
    </set-header>
    <set-header name="TokenB" exists-action="override">
      <value>
        @{ 
          JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>(); 
          return identity.SelectToken("TokenB").ToString(); 
        }
      </value>
    </set-header>
  </send-request>

  <!-- Return response from the second API -->
  <return-response response-variable-name="responseData">
    <set-status code="200" reason="OK" />
    <set-header name="Content-Type" exists-action="override">
      <value>application/json</value>
    </set-header>
    <set-body>
      @{ 
        JObject api_response = ((IResponse)context.Variables["data"]).Body.As<JObject>(); 
        return api_response.ToString();   
      }
    </set-body>
  </return-response>
</inbound>
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是设置第二个标头(令牌 B)的值。看来我无法重新使用上下文变量(IResponse)context.Variables["auth"]

当我查看跟踪时,我看到第一个<set-header>策略的以下输出:

"message":"表达式已成功求值。", "value":"xxxxxxxxxxxxxxxxxxxxx"

但对于第二个<set-header>政策我得到:

“message”:“表达式求值失败。”,“details”:“未将对象引用设置为对象的实例。”

我可以看到,在第一个策略上调用该方法后,我无法再在第二个<set-header>策略中以相同的方式重用上下文变量。

我努力了:

  • 使用设置令牌字符串<set-variable>。我相信可以返回的类型数量有限<set-variable>,并且我无法返回IResponseJObject。如果我尝试转换为 json 然后提取每个属性(TokenA 和 TokenB)的字符串,我会遇到与上面相同的问题。

有人可以帮助我使用语法来复制对象IResponseJObject以便我可以使用 读取它两次吗.SelectToken()?我确信我误解了一个基本概念,但我距离经验丰富的 C# 开发人员还很远!

谢谢

小智 10

您收到错误的原因是您阅读响应正文的方式。当你将正文读作

JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>();

Run Code Online (Sandbox Code Playgroud)

您基本上是从上下文变量中处理主体。因此,下次读取变量主体时,它会抛出臭名昭著的Object reference错误。要在 Azure API 管理中读取主体,您需要preservecontent在代码中使用该属性。所以你会读到如下所示的正文

JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>(preserveContent: true);
Run Code Online (Sandbox Code Playgroud)

当您执行此操作时,原始正文将被保留,并且仅在评估中注入正文的副本。您可以在“设置正文 - APIM 策略”中找到有关此内容的详细文档