
FastAPI로부터 응답을 받았을 때 웹 브라우저에서 한글이 깨지는 경우
어떻게 해결할 수 있는지 알아보자.
지금까지 우리가 작성한 코드는 텍스트 인코딩 방식을 명시하지 않았다.
보통의 웹사이트는 헤더 부분에 charset=utf-8 라는 메타 데이터를 가지고 있어
웹 브라우저가 웹사이트 정보를 받았을 때
UTF-8 방식으로 인코딩되어 있음을 인지할 수 있지만
그것이 명시되어 있지 않을 경우 시스템 기본 인코딩으로 보여준다.
이 '시스템 기본 인코딩'이 UTF-8이 아닌 다른 방식이었을 경우
인코딩 방식이 맞지 않아 잘못 해석된 텍스트가 출력된다.
어차피 개발 단계가 아닌 프로젝트 완성 단계에서는
백엔드의 출력을 웹 브라우저에서 직접 보여줄 일이 없으니
프론트엔드에서 메타 데이터를 제대로 명시하면 문제 없긴 하다.
하지만 개발 단계에서 출력된 데이터를 확인할 수 있어야
정상적으로 작동하는지 원활하게 확인할 수 있으니 적절한 코드로 변경한다.
우리의 이전 실습에서 한글 텍스트를 반환했으니
그 코드를 기준으로 코드를 수정해 보겠다.
app/main.py(수정 전)from fastapi import FastAPI import rust_engine import time app = FastAPI() @app.get("/") def read_root(): return { "status": "200", "info": "비동기 작업 중에도 응답할 수 있습니다." } @app.get("/async-rust/{seconds}") async def run_rust_task(seconds: int): start = time.time() message = await rust_engine.async_compute(seconds) end = time.time() return { "result": message, "duration": f"{end - start:.2f}s", "engine": "Rust (via pyo3-async-runtimes)" }
~/workspace/asynchronous$ curl -i http://127.0.0.1:8000/ HTTP/1.1 200 OK date: Tue, 24 Mar 2026 23:01:06 GMT server: uvicorn content-length: 80 content-type: application/json {"status":"200","info":"비동기 작업 중에도 응답할 수 있습니다."}%
ORJSONResponse를 불러온다.
FastAPI의 기본 응답을 ORJSONResponse로 바꿔주기만 하면 된다.
이를 위해 orjson 라이브러리를 설치해야 한다.
~/workspace/asynchronous$ pip install orjson
기본 응답을 바꾸지 않고 각 함수의 반환값을 일일이
return ORJSONResponse(
content=content,
media_type="application/json; charset=utf-8")
와 같이 변경할 수도 있지만 기본 응답 자체를 바꿔주는 편이 효율적이다.
ORJSONResponse 클래스를 상속받아
media_type 값을 덮어씌운 클래스를 생성하고
FastAPI의 기본 응답을 그것으로 변경해 준다.
app/main.py(수정 후)from fastapi import FastAPI from fastapi.responses import ORJSONResponse import rust_engine import time class UTF8ORJSONResponse(ORJSONResponse): media_type = "application/json; charset=utf-8" app = FastAPI(default_response_class=UTF8ORJSONResponse) @app.get("/") def read_root(): return { "status": "200", "info": "비동기 작업 중에도 응답할 수 있습니다." } @app.get("/async-rust/{seconds}") async def run_rust_task(seconds: int): start = time.time() message = await rust_engine.async_compute(seconds) end = time.time() return { "result": message, "duration": f"{end - start:.2f}s", "engine": "Rust (via pyo3-async-runtimes)" }
~$ curl -i http://127.0.0.1:8000/ HTTP/1.1 200 OK date: Tue, 24 Mar 2026 23:04:15 GMT server: uvicorn content-length: 80 content-type: application/json; charset=utf-8 {"status":"200","info":"비동기 작업 중에도 응답할 수 있습니다."}%
응답의 content-type 에 인코딩 정보가 추가되었다.
웹 브라우저로 테스트 해보아도 한글이 정상 출력되는 것을 확인할 수 있을 것이다.
| 구분 | 표준 JSONResponse | ORJSONResponse |
|---|---|---|
| 직렬화 방식 | Python json.dumps 사용 | orjson.dumps (Rust/C) 사용 |
| 한글 처리 | \uXXXX 로 변환 (이스케이프) | UTF-8 바이트 그대로 유지 |
| 헤더 처리 | 유저가 직접 명시해야 함 | 자동으로 UTF-8로 전송 |
| 성능 | 보통 | 매우 빠름 |
실습의 단순화를 위해 기본값을 사용했지만 사실 성능 측면에서도
ORJSONReponse를 사용하는 편이 이득이다.
코드를 수정하기 전에도 웹 브라우저에는 한글이 깨져도
Swagger UI로 실행하면 응답의 한글이 잘 나온다.
이는 Swaager UI가 웹 브라우저 위에서 실행되는 웹앱인데
내부적으로 fetch() API를 사용하여 데이터를 가져온 뒤
UTF-8 기반으로 HTML 문서 안에 보기 좋게 출력해주기 때문이다.
Swagger UI의 기본 인코딩이 UTF-8이니
따로 명시해주지 않았어도 UTF-8로 해석하고 보여준 것이다.