Browse Source

🐛 Set anti-buffering headers on JSONL streaming responses

Server-Sent Events responses set `Cache-Control: no-cache` and
`X-Accel-Buffering: no` so proxies (e.g. Nginx) deliver events
incrementally instead of buffering the whole response.

JSONL streaming responses are incremental in the same way, but were
missing these headers, so a buffering proxy would hold back the lines
and defeat the streaming. Set the same headers on the JSONL response
for consistency with SSE.
pull/15813/head
Agustin Torres 1 month ago
parent
commit
acda75510c
  1. 3
      fastapi/routing.py
  2. 19
      tests/test_tutorial/test_stream_json_lines/test_tutorial001.py

3
fastapi/routing.py

@ -658,6 +658,9 @@ def get_request_handler(
media_type="application/jsonl", media_type="application/jsonl",
background=solved_result.background_tasks, background=solved_result.background_tasks,
) )
response.headers["Cache-Control"] = "no-cache"
# For Nginx proxies to not buffer the streamed response
response.headers["X-Accel-Buffering"] = "no"
response.headers.raw.extend(solved_result.response.headers.raw) response.headers.raw.extend(solved_result.response.headers.raw)
elif dependant.is_async_gen_callable or dependant.is_gen_callable: elif dependant.is_async_gen_callable or dependant.is_gen_callable:
# Raw streaming with explicit response_class (e.g. StreamingResponse) # Raw streaming with explicit response_class (e.g. StreamingResponse)

19
tests/test_tutorial/test_stream_json_lines/test_tutorial001.py

@ -43,6 +43,25 @@ def test_stream_items(client: TestClient, path: str):
assert lines == expected_items assert lines == expected_items
@pytest.mark.parametrize(
"path",
[
"/items/stream",
"/items/stream-no-async",
"/items/stream-no-annotation",
"/items/stream-no-async-no-annotation",
],
)
def test_stream_sets_streaming_headers(client: TestClient, path: str):
"""JSONL streaming responses should disable proxy buffering and caching,
so intermediaries deliver items incrementally (matching SSE responses)."""
response = client.get(path)
assert response.status_code == 200, response.text
# Tells proxies (e.g. Nginx) not to buffer the streamed response
assert response.headers["x-accel-buffering"] == "no"
assert response.headers["cache-control"] == "no-cache"
def test_openapi_schema(client: TestClient): def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text

Loading…
Cancel
Save