跳到主要内容

proxy-buffering

proxy-buffering 插件为指定路由禁用 NGINX proxy_buffering 指令。这样,上游逐步发送的响应可以立即到达客户端,无需在代理缓冲区中等待。

此行为适用于服务器发送事件(SSE)、Watch API,以及其他发送增量或分块响应的上游服务。

示例​

比较缓冲与增量传输​

以下示例比较 NGINX 的默认响应缓冲行为与通过 proxy-buffering 禁用缓冲的路由。测试上游声明固定的响应长度,并每隔两秒发送一行,共发送三行。启用缓冲的路由会一次性传输全部三行,而禁用缓冲的路由会在每行到达时立即传输。

为流式上游创建以下 Python 脚本:

stream-server.py
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import time

class Handler(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"

def do_GET(self):
chunks = [b"one\n", b"two\n", b"three\n"]

self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(sum(map(len, chunks))))
self.send_header("Connection", "close")
self.end_headers()

for chunk in chunks:
self.wfile.write(chunk)
self.wfile.flush()
time.sleep(2)

self.close_connection = True

def log_message(self, *_):
pass

ThreadingHTTPServer(("0.0.0.0", 8000), Handler).serve_forever()

在网关使用的环境中启动上游:

将 GATEWAY_CONTAINER 设置为正在运行的 APISIX 或 API7 Gateway 容器名称。创建专用网络并将网关连接到该网络:

export GATEWAY_CONTAINER=replace-with-gateway-container-name

docker network create gateway-stream-net
docker network connect gateway-stream-net "$GATEWAY_CONTAINER"

在包含 stream-server.py 的目录中启动流式服务器:

docker run -d \
--name stream-server \
--network gateway-stream-net \
-v "$PWD/stream-server.py:/stream-server.py:ro" \
python:3.13.15-alpine3.24 \
python -u /stream-server.py

创建两条指向同一上游的路由。第一条路由使用 NGINX 默认缓冲行为,第二条路由通过 proxy-buffering 禁用缓冲:

创建不使用 proxy-buffering 的基准路由:

curl "http://127.0.0.1:9180/apisix/admin/routes/proxy-buffering-on" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/buffered",
"upstream": {
"type": "roundrobin",
"nodes": {
"stream-server:8000": 1
}
}
}'

创建禁用缓冲的对比路由:

curl "http://127.0.0.1:9180/apisix/admin/routes/proxy-buffering-off" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/unbuffered",
"plugins": {
"proxy-buffering": {
"disable_proxy_buffering": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"stream-server:8000": 1
}
}
}'

创建一个 Python 客户端,用于记录每一行响应可用的时间:

stream-client.py
import time
import urllib.request

for path in ("buffered", "unbuffered"):
start = time.monotonic()
print(path)

with urllib.request.urlopen(f"http://127.0.0.1:9080/{path}") as response:
for line in response:
elapsed = time.monotonic() - start
print(f"{elapsed:.1f}s {line.decode().strip()}")

运行客户端:

python stream-client.py

基准路由应在约四秒后一次性返回全部三行。使用 proxy-buffering 的路由则应在上游写入每一行时立即返回:

buffered
4.0s one
4.0s two
4.0s three
unbuffered
0.0s one
2.0s two
4.0s three

此差异表明,proxy-buffering 已为配置的路由禁用 NGINX 响应缓冲。