핵심 정리
{
"lang": "한국어",
"emoji": "😀",
"escaped": "\uD83D\uDE00"
}문법
네트워크 교환 JSON은 UTF-8이어야 한다 — RFC 8259가 이를 사실상 강제한다
RFC 8259는 닫힌 시스템 내부가 아닌 네트워크를 통해 교환되는 JSON text를 UTF-8로 인코딩해야 한다고 명시합니다. UTF-16이나 UTF-32로 저장된 JSON 파일을 읽을 수 있는 파서도 있지만, 상호운용성을 보장하는 유일한 선택은 UTF-8입니다. 실무에서 이 오류는 파일 저장 인코딩과 HTTP 응답 인코딩이 어긋날 때 주로 나타납니다. JSON 자체의 문법은 유효해도 애플리케이션에서 한글이나 이모지가 깨지는 현상이 발생하며, 이때 진단 포인트는 파일 인코딩, Content-Type 헤더의 charset, 데이터베이스 컬럼 charset을 순서대로 확인하는 것입니다.
BOM을 포함하면 일부 파서가 실패한다 — 생성 시에는 BOM을 붙이지 않아야 한다
UTF-8 BOM(Byte Order Mark, \xEF\xBB\xBF)은 일부 Windows 도구가 파일 앞에 자동으로 추가합니다. JSON 파서가 BOM을 무시하고 정상 처리하기도 하지만, 표준 파서 중 BOM을 오류로 처리하는 것도 있습니다. RFC 8259는 JSON text 생성 시 BOM을 포함하지 않아야 한다고 명시합니다. 특히 Windows 환경 메모장에서 저장할 때 "UTF-8 BOM 있음"으로 저장하면 이 문제가 생기기 쉽습니다. Node.js나 Python으로 JSON 파일을 쓸 때도 utf-8-sig 인코딩 대신 utf-8을 명시적으로 지정해야 합니다.
Unicode 문자는 직접 쓰거나 escape로 쓸 수 있다 — 두 형태는 동일한 값이다
JSON string은 Unicode 문자를 두 가지 방식으로 표현할 수 있습니다. "한국어"처럼 직접 문자로 쓰거나, "\uD55C\uAD6D\uC5B4"처럼 \uXXXX escape 형태로 쓸 수 있습니다. 두 형태는 의미상 동일하며, JSON 파서는 둘 다 같은 문자열로 읽어야 합니다. BMP 밖의 문자(이모지 등, U+10000 이상)는 surrogate pair 두 개로 escape 해야 합니다("\uD83D\uDE00"이 😀). 이 점이 헷갈리면 이모지나 특수 기호를 직접 문자로 쓰는 것이 더 명확합니다.
같은 문자의 다른 표현이 문자열 비교 오류를 만들 수 있다
"A"와 "\u0041"은 동일한 JSON string이지만, 일부 파서나 라이브러리가 raw bytes를 비교하면 다른 값으로 처리할 수 있습니다. 또한 Unicode 정규화 형태(NFC, NFD)가 다르면 육안으로 같아 보이는 문자열이 byte 수준에서 다릅니다. 한글 조합형/완성형처럼 같은 글자를 다른 Unicode 코드 포인트 조합으로 표현할 수 있는 경우가 그 예입니다. 문자열 검색, 해시, 고유성 판단에서 이 문제를 피하려면 Unicode 정규화(NFC)를 저장 전에 적용하는 것이 안전합니다.
이 문제는 "문자 깨짐"이 아니라 "같아 보이는데 비교가 실패하는 문제"라서 더 늦게 발견됩니다. 사용자 이름, 태그, 검색 키처럼 동일성 판단이 중요한 값은 인코딩뿐 아니라 정규화 전략까지 같이 정해야 합니다.
{
"lang": "한국어",
"emoji": "😀",
"escaped": "\uD83D\uDE00"
}체크포인트
| 상황 | 적합한 선택 |
|---|---|
| 네트워크 교환용 JSON 인코딩 | UTF-8 (BOM 없음) |
| 이모지·한글을 JSON에 담을 때 | 직접 문자 또는 \uXXXX escape (동일한 의미) |
| 파일 저장 인코딩 확인 | UTF-8 without BOM 선택 |
| 문자열 비교·검색이 중요한 경우 | NFC 정규화 후 저장 |
| 파싱은 되는데 값 비교가 이상할 때 | 정규화 형태(NFC/NFD) 차이 확인 |
주의할 점
JSON이 깨졌다고 느껴질 때 실제 원인이 문법이 아니라 인코딩인 경우가 많습니다. 파일 저장 인코딩, HTTP Content-Type charset, 데이터베이스 컬럼 charset이 모두 UTF-8로 일치해야 합니다. BOM이 있는 UTF-8 파일은 일부 파서에서 오류를 내므로, 생성 단계에서 BOM 없는 UTF-8로 통일하는 것이 가장 안전합니다.
\xEF\xBB\xBF{ "name": "Kim" }UTF-8 BOM이 파일 앞에 붙으면 일부 파서는 이를 JSON 본문 앞의 이상한 문자로 해석해 실패합니다. 파일이 "맞아 보이는데도" 파싱이 안 되면 BOM 여부부터 확인하는 편이 빠릅니다.
반대로 파싱은 되는데 검색과 중복 체크가 이상하면 BOM보다 정규화 차이를 먼저 의심해야 합니다. 인코딩 문제와 문자열 동일성 문제는 비슷해 보여도 원인이 다릅니다.
참고 링크
2 sources