FastAPI 에서의 No Content (204) 응답 시 꼭 해줘야 하는 것

204 No Content
204 No Content - HTTP | MDN
The HTTP 204 No Content success status response code indicates that a request has succeeded, but that the client doesn’t need to navigate away from its current page.

RFC 7230 문서에 의하면, 204 응답의 경우 Content-Length
를 헤더로 갖고있을 수 없도록 되어있다. (https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2) 하지만 FastAPI에서는 쉽게 실수함으로써 표준을 지키지 않음과 동시에 인프라 레이어에서 거슬리는 상황이 생길 수 있다.
FastAPI 에서의 204 처리
@app.post('/return-none/', status_code=204, response_model=DeleteItemResponse)
async def delete_item():
pass
reponse_model
지정이런 식으로 코드를 사용하였을 때, 서버를 구동시킬 수 없다. AssertionError: Status code 204 must not have a response body
라는 에러를 발생하면서.
여기까진 좋다. 하지만, 개발자들은 새로운 문제를 일으킬 수 있다.
@app.post('/return-none/', status_code=204)
async def return_none():
pass
@app.post('/return-none-explicit/', status_code=204)
async def return_none_explicit():
return None
이런 식으로 None을 return 하도록 하게 되면, FastAPI, Starlette 는 아래와 같은 response 를 주고 있다.
{'date': 'Wed, 22 Dec 2021 18:22:27 GMT', 'server': 'uvicorn', 'content-length': '4', 'content-type': 'application/json'}
datadog같은 APM에서 이런 warning 로그를 확인할 수 있을 것이다.
2021/12/24 07:53:43 [warn] 5196#5196: *1047308 upstream sent more data than specified in "Content-Length" header while reading upstream, client: 119.205.223.214, server: <🔗>, request: "POST <🔗> HTTP/1.1", upstream: "http://10.0.0.39:80/<🔗>", host: "<🔗>"
문제 해결
from fastapi import Response
@app.post('/return-http-response/', status_code=204)
async def return_http_response():
return Response(status_code=204)
이렇게 Response
객체를 명시적으로 리턴해주면 문제 없다. content-length
와 content-type
이 없는 response headers를 확인할 수 있을 것이다.
{'date': 'Wed, 22 Dec 2021 18:21:31 GMT', 'server': 'uvicorn'}
이를 해결하려고 하는 PR은 FastAPI 와 Starlette 에 모두 존재한다. 하지만, 머지가 되려면 갈 길이 여러모로 멀어보인다.