diff --git a/fastapi/routing.py b/fastapi/routing.py index 4a55fda8a..563531d91 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -658,6 +658,9 @@ def get_request_handler( media_type="application/jsonl", 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) elif dependant.is_async_gen_callable or dependant.is_gen_callable: # Raw streaming with explicit response_class (e.g. StreamingResponse) diff --git a/tests/test_tutorial/test_stream_json_lines/test_tutorial001.py b/tests/test_tutorial/test_stream_json_lines/test_tutorial001.py index 0b5f9d95b..783f74a85 100644 --- a/tests/test_tutorial/test_stream_json_lines/test_tutorial001.py +++ b/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 +@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): response = client.get("/openapi.json") assert response.status_code == 200, response.text