Azure API 管理刷新缓存响应

Azure API Management refresh cached response

我正在使用 API 管理和外部 Azure 缓存 Redis 来缓存到达外部服务的响应。我需要提供一种机制,通过从服务器重新获取数据来使缓存的响应无效 - 进而使用新响应更新缓存。

我当前的策略(如下所示)在缓存响应过期或收到带有 Cache-Control: must-revalidate header 的新请求时从服务器接收 up-to-date 数据。同样,当收到 header 时,我想用新响应更新缓存的响应。我在概念上或在我的政策中是否遗漏了什么?

<policies>
    <inbound>
        <base />
        <set-backend-service id="apim-generated-policy" backend-id="func-myapp-dev-001" />
        <set-variable name="mustRevalidate" value="@(context.Request.Headers.GetValueOrDefault("Cache-Control","").Contains("must-revalidate"))" />
        <choose>
            <when condition="@(context.Variables.GetValueOrDefault<bool>("mustRevalidate") == false)">
                <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" allow-private-response-caching="true" />
            </when>
        </choose>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <set-header name="Cached-At" exists-action="override">
            <value>@(System.DateTime.Now.ToString())</value>
        </set-header>
        <cache-store duration="360" />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

问题是 <cache-store> 不能没有 <cache-lookup><cache-lookup>不仅从缓存中获取缓存值,而且也是<cache-store>的一种配置。您可以在跟踪中亲眼看到。当您使用 Control-Cache: must-revalidate header 调用您的 API 时,<cache-lookup> 不会因为您的 <when> 策略而被触发,而且 <cache-store> 也不会不幸的是,被触发了。在日志中,您将看到消息:

cache-store (0.019 ms) "Corresponding cache-lookup policy was not applied. Skipping cache-store."

好了。跳过 <cache-lookup> 将从后端获得新的响应,但不会为以后的请求缓存它。


至于怎么达到你想要的

我已经检查了两次,但不幸的是 <cache-lookup> 没有根据参数跳过查找的选项。

也在考虑不同的方法。我认为这可以使用 <cache-lookup-value> 策略。一开始,根据您的 must-revalidate 参数,如果它设置为 true,您可以删除缓存的值。然后正常进行。最难的部分是考虑可以根据请求生成缓存键的机制。 APIM 在 cache-store 中做同样的事情。密钥在不同请求之间必须是唯一的,但对于同一请求必须是相同的——就像缓存一样。 APIM 申请缓存键的模式是这样的(你可以查看跟踪):

"cacheKey": "{apimName}.{apiId};{revision};{backendurl with all query parameters}"

我的例子 API:

"cacheKey": "my-apim.azure-api.net.1_weatherbit-io;rev=1.2432_get-current-city_id-city_id-key-key_4_https_api.weatherbit.io_443_/v2.0/current?city_id=4487042"

一旦你有了一些智能密钥生成,我认为你就可以开始了,最终的解决方案可能如下所示:

<policies>
    <inbound>
        <set-variable name="cacheKey" value="@{
            return ""; // here implement some smart key generation based on the request parameters from context. 
        }" />
        <set-variable name="mustRevalidate" value="@(context.Request.Headers.GetValueOrDefault("Cache-Control","").Contains("must-revalidate"))" />
        <choose>
            <when condition="@(context.Variables.GetValueOrDefault<bool>("mustRevalidate") == true)">
                <cache-remove-value key="@(context.Variables.GetValueOrDefault<string>("cacheKey"))" />
            </when>
        </choose>
        <cache-lookup-value key="@(context.Variables.GetValueOrDefault<string>("cacheKey"))" variable-name="cachedResponse" />
        <choose>
            <when condition="@(context.Variables.GetValueOrDefault<JObject>("cachedResponse") != (JObject)null)">
                <return-response>
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json; charset=utf-8</value>
                    </set-header>
                    <set-body>@{
                        return context.Variables.GetValueOrDefault<JObject>("cachedResponse").ToString();
                    }</set-body>
                </return-response>
            </when>
        </choose>
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <cache-store-value key="@(context.Variables.GetValueOrDefault<string>("cacheKey"))" value="@(context.Response.Body.As<JObject>(preserveContent: true))" duration="30" />
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

当然这只缓存响应,如果你想缓存 headers 以及你必须实现如何存储它的机制,然后什么时候到 return 它在 <return-response> 中,如何将其解析为 header 和 body。我希望你能看到这个解决方案的缺点是什么,你需要自己实施一切。您不能再使用 <cache-lookup><cache-store> 的 built-in 功能。但同时你有更多的自由,可以实现你想要的。无论如何,祝你好运。

PS。 <cache-store-value> 策略具有 caching-type 属性。您可以使用它来将缓存更改为外部缓存。