跳到主要内容

proxy-cache

proxy-cache 插件根据缓存键缓存 HTTP 响应,从而减少向上游服务重复发送的请求。该插件支持磁盘和内存两种缓存方式,可缓存 GET、POST 和 HEAD 请求。

可以根据请求 HTTP 方法、响应状态码、请求头值等条件有选择地缓存响应。

默认情况下,已认证消费者使用相互隔离的有效缓存键。除非启用 cache_set_cookie,否则内存缓存策略不会缓存包含 Set-Cookie 的响应;对于上游标记为 private、no-store 或 no-cache 的响应则一律不缓存。

示例​

以下示例演示了如何在不同场景下配置 proxy-cache。

在磁盘上缓存数据​

磁盘缓存的容量比内存缓存更大;如果缓存目录使用持久化存储,它还可以在网关重启后保留缓存响应。磁盘缓存适用于持久性比最低缓存访问延迟更重要的场景。

以下示例演示了如何在路由上使用 proxy-cache 插件将响应缓存在磁盘上。

使用磁盘缓存策略时,缓存 TTL 由 Expires 或 Cache-Control 响应头决定。如果两个响应头均不存在,或者网关因上游不可用而返回 502 Bad Gateway 或 504 Gateway Timeout,缓存 TTL 将使用配置文件中配置的默认值。

创建一个使用 proxy-cache 插件的路由以在磁盘上缓存数据:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"cache_strategy": "disk"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'

向路由发送请求:

curl -i "http://127.0.0.1:9080/anything"

你应该会看到 HTTP/1.1 200 OK 响应,并带有以下响应头,表明插件已成功启用:

Apisix-Cache-Status: MISS

由于第一个响应之前没有可用缓存,因此显示 Apisix-Cache-Status: MISS。

在缓存 TTL 窗口内再次发送相同的请求。你应该会看到 HTTP/1.1 200 OK 响应,并带有以下响应头,表明缓存命中:

Apisix-Cache-Status: HIT

等待缓存超过 TTL 后过期,然后再次发送相同的请求。你应该会看到 HTTP/1.1 200 OK 响应,并带有以下响应头,表明缓存已过期:

Apisix-Cache-Status: EXPIRED

在内存中缓存数据​

内存缓存的访问延迟比磁盘缓存更低,但无法在网关重启后保留缓存响应。它适合缓存能够再次从上游服务获取的临时响应。

内存缓存策略会根据上游 Vary 响应头列出的请求头计算不同变体,并分别缓存响应;带有 Vary: * 的响应不会被缓存。该行为自 API7 企业版 3.9.14、3.10.0 和 APISIX 3.17.0 起提供。

以下示例演示了如何在路由上使用 proxy-cache 插件将响应缓存在内存中。

创建一个使用 proxy-cache 的路由并将其配置为使用基于内存的缓存:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"cache_strategy": "memory",
"cache_zone": "memory_cache",
"cache_ttl": 10
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'

❶ cache_strategy:使用内存缓存策略。

❷ cache_zone:选择已配置的内存缓存区域。

❸ cache_ttl:每个缓存响应保留 10 秒。

向路由发送请求:

curl -i "http://127.0.0.1:9080/anything"

你应该会看到 HTTP/1.1 200 OK 响应,并带有以下响应头,表明插件已成功启用:

Apisix-Cache-Status: MISS

由于第一个响应之前没有可用缓存,因此显示 Apisix-Cache-Status: MISS。

在缓存 TTL 窗口内再次发送相同的请求。你应该会看到 HTTP/1.1 200 OK 响应,并带有以下响应头,表明缓存命中:

Apisix-Cache-Status: HIT

手动清除缓存​

虽然缓存响应通常会根据 TTL 过期,但你可能需要在缓存过期前清除缓存数据。

以下示例演示了如何使用 PURGE 方法清除磁盘上的缓存数据。PURGE 也支持内存缓存;如需测试,请使用上一个示例中的内存缓存配置。

将 PURGE 请求发送到与缓存请求相同的路由 URI。插件为 PURGE 请求派生缓存键的方式与填充缓存的请求相同。请使用相同的主机、URI、查询参数以及 cache_key 引用的任何其他值。如果缓存键按消费者隔离,请以同一消费者身份发送请求。

PURGE 会删除同一有效基础缓存键下索引的所有内存 Vary 变体。该行为自 API7 企业版 3.9.14、3.10.0 和 APISIX 3.17.0 起提供。

创建一个将响应缓存到磁盘的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"cache_strategy": "disk"
}
},
"upstream": {
"type": "roundrobin",
"pass_host": "node",
"scheme": "https",
"nodes": {
"httpbingo.org:443": 1
}
}
}'

发送请求以填充缓存:

curl -i "http://127.0.0.1:9080/anything"

再次发送相同的请求,并验证响应中包含 Apisix-Cache-Status: HIT。

向同一 URI 发送 PURGE 请求:

curl -i "http://127.0.0.1:9080/anything" -X PURGE

你应该会看到 HTTP/1.1 200 OK 响应,表明缓存响应已清除。如果没有与缓存键匹配的缓存响应,插件将返回 HTTP/1.1 404 Not Found。

再次向路由发送 GET 请求:

curl -i "http://127.0.0.1:9080/anything"

你应该会看到以下响应头,表明先前的缓存响应已不可用:

Apisix-Cache-Status: MISS

有条件地缓存响应​

以下示例演示了如何配置 proxy-cache 插件以有条件地缓存响应。

创建一个使用 proxy-cache 插件的路由并配置 no_cache 属性:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything/no-cache",
"plugins": {
"proxy-cache": {
"no_cache": ["$arg_no_cache", "$http_no_cache"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'

❶ no_cache:按顺序拼接查询参数 no_cache 和请求头 no_cache。如果拼接结果既不为空,也不完全等于 0,则不会存储响应。

多次发送以下请求。查询参数会阻止每个上游响应写入缓存:

curl -i "http://127.0.0.1:9080/anything/no-cache?no_cache=1"

每个响应都应返回 HTTP/1.1 200 OK,并包含以下响应头:

Apisix-Cache-Status: MISS

接下来多次发送以下请求。值 0 允许将响应写入缓存:

curl -i "http://127.0.0.1:9080/anything/no-cache?no_cache=0"

第一次响应应为缓存未命中,后续响应应包含:

Apisix-Cache-Status: HIT

也可以通过请求头提供相同的条件。多次发送以下请求:

curl -i "http://127.0.0.1:9080/anything/no-cache" -H "no_cache: 1"

每个响应都应保持为缓存未命中:

Apisix-Cache-Status: MISS

有条件地从缓存检索响应​

以下示例演示了如何配置 proxy-cache 插件以有条件地从缓存中检索响应。

创建一个使用 proxy-cache 插件的路由并配置 cache_bypass 属性:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"cache_bypass": ["$arg_bypass", "$http_bypass"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'

❶ cache_bypass:按顺序拼接查询参数 bypass 和请求头 bypass。如果拼接结果既不为空,也不完全等于 0,则跳过缓存读取。

使用指示缓存绕过的 URL 参数 bypass 值向路由发送请求:

curl -i "http://127.0.0.1:9080/anything?bypass=1"

你应该会看到 HTTP/1.1 200 OK 响应,并带有以下响应头:

Apisix-Cache-Status: BYPASS

使用 URL 参数 bypass 值为零向路由发送另一个请求:

curl -i "http://127.0.0.1:9080/anything?bypass=0"

你应该会看到 HTTP/1.1 200 OK 响应,并带有以下响应头:

Apisix-Cache-Status: MISS

也可以通过 bypass 请求头指定该值:

curl -i "http://127.0.0.1:9080/anything" -H "bypass: 1"

应绕过缓存:

Apisix-Cache-Status: BYPASS

缓存网关生成的 502 和 504 响应​

当网关无法连接上游服务时,磁盘缓存会存储网关生成的 502 Bad Gateway 和 504 Gateway Timeout 响应。默认不缓存其他 5xx 响应。

以下示例使用固定版本的 HTTPBin 镜像和一个有意延迟的端点。请按所用配置工作流启动示例上游:

在网关所用的 Docker 网络中运行示例上游。以下命令使用 APISIX Docker Quickstart 创建的网络;其他 Docker 部署请替换网络名称:

docker run -d --name proxy-cache-httpbin \
--network apisix-quickstart-net \
ghcr.io/mccutchen/go-httpbin:2.25.0

创建一条将上游请求重写到 /delay/3、并在一秒后停止等待的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes/proxy-cache-timeout" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/timeout",
"plugins": {
"proxy-rewrite": {
"uri": "/delay/3"
},
"proxy-cache": {}
},
"upstream": {
"type": "roundrobin",
"retries": 0,
"timeout": {
"connect": 1,
"send": 1,
"read": 1
},
"nodes": {
"proxy-cache-httpbin:8080": 1
}
}
}'

向路由发送请求:

curl -i "http://127.0.0.1:9080/timeout"

大约一秒后,响应应包含以下状态和响应头:

HTTP/1.1 504 Gateway Time-out
Apisix-Cache-Status: MISS

再次发送相同请求。网关应立即返回已缓存的错误响应:

curl -i "http://127.0.0.1:9080/timeout"

响应应包含:

HTTP/1.1 504 Gateway Time-out
Apisix-Cache-Status: HIT

默认不缓存其他 5xx 状态码的响应,例如 503 Service Unavailable。