使用APIM入站send-request策略时无法实现内部响应缓存
问题分析与解决方案
首先明确:可以缓存send-request返回的响应,但你的策略存在两个核心问题导致缓存失效:
return-response跳过了outbound阶段:你在inbound里用return-response直接返回结果,会跳过后续的backend和outbound阶段,导致outbound中的cache-store永远不会执行,缓存根本没机会被写入。- 缓存查询时机与逻辑不匹配:
cache-lookup放在最前面时缓存无对应数据,必然返回miss,且后续没有正确的缓存写入逻辑支撑。
修正后的策略代码(推荐方案)
调整策略流程,确保缓存写入逻辑能正常执行,同时保证缓存命中逻辑有效:
<policies> <inbound> <base /> <!-- 优先从缓存查询,命中则直接返回 --> <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none"> <vary-by-header>Accept</vary-by-header> <vary-by-header>Accept-Charset</vary-by-header> </cache-lookup> <!-- 缓存未命中时,执行表存储查询 --> <set-variable name="SASToken" value="@("my sas key")" /> <set-variable name="TableURL" value="@{string sastoken = context.Variables.GetValueOrDefault<string>("SASToken");return String.Format("https://storageaccount.table.core.windows.net/table()?{0}", sastoken);}" /> <send-request mode="new" response-variable-name="data" timeout="20" ignore-error="false"> <set-url>@($"{context.Variables.GetValueOrDefault("TableURL")}")</set-url> <set-method>GET</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-header name="Accept" exists-action="override"> <value>application/json;odata=nometadata</value> </set-header> </send-request> <!-- 构造响应到context.Response,不直接终止流程 --> <set-status code="200" reason="Ok" /> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-header name="Accept" exists-action="override"> <value>application/json;odata=nometadata</value> </set-header> <set-body template="liquid"> { "result" : [ {{body}} ] } </set-body> </inbound> <backend> <base /> </backend> <outbound> <base /> <!-- 响应构造完成后,存入缓存 --> <cache-store duration="1000" cache-response="true" /> </outbound> <on-error> <base /> </on-error> </policies>
关键调整说明
- 移除
return-response:改用set-status、set-header、set-body直接修改context.Response,让流程能走到outbound阶段,确保cache-store执行。 - 缓存逻辑顺序:先执行
cache-lookup,APIM会自动在命中时返回缓存响应;未命中则执行数据查询与响应构造,最后在outbound完成缓存写入。 - 缓存键一致性:
cache-lookup的vary-by-header配置与请求头匹配,确保后续请求能正确匹配缓存键。
备选方案(保留return-response)
如果必须使用return-response,可在构造响应后手动调用cache-store,指定要缓存的响应变量:
<policies> <inbound> <base /> <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none"> <vary-by-header>Accept</vary-by-header> <vary-by-header>Accept-Charset</vary-by-header> </cache-lookup> <set-variable name="SASToken" value="@("my sas key")" /> <set-variable name="TableURL" value="@{string sastoken = context.Variables.GetValueOrDefault<string>("SASToken");return String.Format("https://storageaccount.table.core.windows.net/table()?{0}", sastoken);}" /> <send-request mode="new" response-variable-name="data" timeout="20" ignore-error="false"> <set-url>@($"{context.Variables.GetValueOrDefault("TableURL")}")</set-url> <set-method>GET</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-header name="Accept" exists-action="override"> <value>application/json;odata=nometadata</value> </set-header> </send-request> <!-- 构造最终响应并存入变量 --> <set-variable name="finalResponse" value="@{ var data = context.Variables.GetValueOrDefault<Response>("data"); var body = data.Body.As<string>(); return new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent($"{{\"result\": [{body}]}}", Encoding.UTF8, "application/json") }; }" /> <!-- 手动存入缓存 --> <cache-store duration="1000" cache-response="true" response-variable-name="finalResponse" /> <!-- 返回响应 --> <return-response response-variable-name="finalResponse" /> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
内容的提问来源于stack exchange,提问作者CSR
相关产品推荐
相关产品推荐

