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
属性。您可以使用它来将缓存更改为外部缓存。
我正在使用 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
属性。您可以使用它来将缓存更改为外部缓存。