Browse Source

Merge ac2138551e into eb75fd078e

pull/15813/merge
Agustin Torres 4 days ago
committed by GitHub
parent
commit
11f3af13e2
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      docs/en/docs/tutorial/stream-json-lines.md
  2. 4
      fastapi/routing.py
  3. 18
      tests/test_tutorial/test_stream_json_lines/test_tutorial001.py

12
docs/en/docs/tutorial/stream-json-lines.md

@ -72,6 +72,18 @@ If you want to stream binary data, for example video or audio, check the advance
///
## Proxy Buffering { #proxy-buffering }
When a JSON Lines response is served behind a proxy that buffers responses by default (for example Nginx with `proxy_buffering on`), the proxy could hold back the lines and deliver them all at once, which would defeat the streaming.
To prevent that, FastAPI sets the `X-Accel-Buffering: no` header on JSON Lines responses, telling Nginx (and compatible proxies) not to buffer them.
/// note
Caching headers (like `Cache-Control`) are **not** set automatically, they are left up to you. JSON Lines is also used for bulk exports where caching can be legitimate, so FastAPI doesn't impose a caching policy. If you need one, you can set it on the [`Response`](../advanced/response-headers.md).
///
## Stream JSON Lines with FastAPI { #stream-json-lines-with-fastapi }
To stream JSON Lines with FastAPI you can, instead of using `return` in your *path operation function*, use `yield` to produce each item in turn.

4
fastapi/routing.py

@ -665,6 +665,10 @@ def get_request_handler(
media_type="application/jsonl",
background=solved_result.background_tasks,
)
# For Nginx proxies to not buffer the streamed response.
# Caching headers are intentionally left to the user, as JSONL
# is also used for bulk exports where caching can be legitimate.
response.headers["X-Accel-Buffering"] = "no"
response.headers.raw.extend(solved_result.response.headers.raw)
elif dependant.is_async_gen_callable or dependant.is_gen_callable:
# Raw streaming with explicit response_class (e.g. StreamingResponse)

18
tests/test_tutorial/test_stream_json_lines/test_tutorial001.py

@ -43,6 +43,24 @@ def test_stream_items(client: TestClient, path: str):
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_disables_proxy_buffering(client: TestClient, path: str):
"""JSONL streaming responses should disable proxy buffering, so
intermediaries (e.g. Nginx) deliver items incrementally instead of
holding them back until the buffer fills."""
response = client.get(path)
assert response.status_code == 200, response.text
assert response.headers["x-accel-buffering"] == "no"
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

Loading…
Cancel
Save