1

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

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

  • 用于<send-request>向 API 的身份验证端点发出请求。
  • 身份验证 API 返回两个密钥,它们必须作为 http 标头包含,以便能够向其他端点发出后续请求。
  • 我正在使用将来自身份验证 API 的响应解析为 jsonJObject
  • 然后我试图从 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>

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

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

"message":"表达式评估成功。", "value":"xxxxxxxxxxxxxxxxxxxxx"

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

"message":"表达式评估失败。", "details":"对象引用未设置为对象的实例。"

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

我努力了:

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

有人可以帮助我使用允许我复制IResponse对象的语法,或者JObject让我可以使用它来阅读它两次.SelectToken()吗?我确定我误解了一个基本概念,但我远非经验丰富的 C# 开发人员!

谢谢

4

1 回答 1

6

您收到错误的原因是您阅读响应正文的方式。当你把身体读成

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

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

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

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

于 2020-05-15T07:35:43.197 回答