Azure API Management缓存配置:缓存响应并跨端点失效
我有一个连接Azure Function的Azure API Management(通过Function App自动生成API),包含以下端点:
- GET /GetEvents
- POST /AddEvent
- ...
事件添加操作不频繁但访问量高,需要实现:缓存GET /GetEvents的完整响应,调用POST /AddEvent时让该缓存失效。
之前使用cache-store和cache-lookup策略的配置如下:
<policies> <inbound> <base /> <set-backend-service id="apim-generated-policy" backend-id="app-test" /> <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" allow-private-response-caching="true" must-revalidate="false" downstream-caching-type="public" /> </inbound> <backend> <base /> </backend> <outbound> <base /> <cache-store duration="@((new Random(context.RequestId.GetHashCode()).Next(40, 50)) * 3 * 60)" /> </outbound> <on-error> <base /> </on-error> </policies>
但尝试用cache-remove-value删除缓存时,发现Redis中的缓存键是自动生成的(格式类似3_apimpbdhsanlkcmeaojfcewjfdsabucbeiuaw1qazerfvg.12345678_app-test;rev=1.11111111_get-getevents.12345678_4_https_apim.azure-api.net_443_/app-test/GetEvents),无法直接指定键值删除。
之后尝试用cache-store-value和cache-lookup-value自定义键值,但序列化响应失败,配置如下:
<policies> <inbound> <base /> <set-backend-service id="apim-generated-policy" backend-id="app-test" /> <cache-lookup-value key="GetEvents" variable-name="eventsList" /> </inbound> <backend> <!--base: Begin Global scope--> <forward-request /> <!--base: End Global scope--> </backend> <outbound> <base /> <cache-store-value key="GetEvents" value="@(JsonConvert.SerializeObject(context.Response.Body.AsFormUrlEncodedContent()))" duration="@((new Random(context.RequestId.GetHashCode()).Next(40, 50)) * 3 * 60)" /> </outbound> <on-error> <base /> </on-error> </policies>
现在有两个问题:
- 是否可以使用
cache-store指定缓存条目键值,以便在其他端点通过cache-remove-value策略删除? - 是否可以存储某个端点的完整响应(类似
cache-lookup的效果),并通过另一个端点使该缓存失效?
问题1:能否用cache-store指定缓存键值?
不行。cache-store和cache-lookup是APIM自动管理缓存键的策略,生成的键包含请求上下文信息(如API名称、路径、协议等)且带有随机前缀,无法手动指定固定键值,因此无法直接通过cache-remove-value匹配删除。
问题2:如何存储完整响应并跨端点失效缓存?
可以通过cache-lookup-value+cache-store-value配合条件策略实现,核心是正确读取和序列化响应内容,具体配置如下:
1. 为GET /GetEvents配置缓存逻辑
<policies> <inbound> <base /> <set-backend-service id="apim-generated-policy" backend-id="app-test" /> <!-- 先尝试从缓存读取数据 --> <cache-lookup-value key="GetEventsCache" variable-name="cachedEvents" /> <!-- 如果缓存命中,直接返回缓存内容,跳过后端请求 --> <choose> <when condition="@(context.Variables.ContainsKey("cachedEvents"))"> <set-body>@((string)context.Variables["cachedEvents"])</set-body> <set-status code="200" reason="OK" /> <return-response /> </when> </choose> </inbound> <backend> <forward-request /> </backend> <outbound> <base /> <!-- 将完整响应内容转为字符串存入缓存 --> <cache-store-value key="GetEventsCache" value="@(context.Response.Body.As<string>())" duration="@((new Random(context.RequestId.GetHashCode()).Next(40, 50)) * 3 * 60)" /> </outbound> <on-error> <base /> </on-error> </policies>
2. 为POST /AddEvent配置缓存失效逻辑
<policies> <inbound> <base /> <set-backend-service id="apim-generated-policy" backend-id="app-test" /> </inbound> <backend> <forward-request /> </backend> <outbound> <base /> <!-- 删除指定的缓存键 --> <cache-remove-value key="GetEventsCache" /> </outbound> <on-error> <base /> </on-error> </policies>
关键说明
- 使用
context.Response.Body.As<string>()可以正确读取响应的字符串内容,避免序列化错误; - 通过
<choose>+<when>判断缓存是否命中,命中则直接返回缓存内容,无需调用后端; POST /AddEvent处理完成后,用cache-remove-value删除固定键GetEventsCache,实现缓存失效。
内容的提问来源于stack exchange,提问作者MrHutnik

