[EXT-033][실무] 나뉘어 온 UTF-8 글자 안전하게 잇기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[EXT-033][실무] 나뉘어 온 UTF-8 글자 안전하게 잇기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 8회 작성일 26-09-08 23:38

본문

[이번 수업]

파일이나 네트워크 데이터는 작은 바이트 조각으로 나뉘어 올 수 있습니다. UTF-8 한 글자를 이루는 바이트도 조각 경계에서 갈라질 수 있습니다. 이번에는 TextDecoder의 stream 옵션으로 아직 끝나지 않은 글자를 보관하고 다음 조각과 안전하게 잇습니다.

[선수지식]

EXT-032에서 배운 UTF-8, Uint8Array, TextEncoder와 TextDecoder의 기본 사용법이 필요합니다. JavaScript 변수와 try/catch를 알고 Node.js 파일을 실행할 수 있으면 됩니다.

[학습목표]

1. 바이트 조각의 경계와 문자 경계가 다를 수 있음을 설명한다.
2. 같은 TextDecoder와 { stream: true }로 조각을 순서대로 처리한다.
3. 입력 종료 때 decode()를 호출해 남은 상태를 마무리한다.

[핵심개념]

청크(chunk)는 스트림에서 한 번에 받은 데이터 조각입니다. UTF-8에서 영문 A는 1바이트지만 한글 ‘한’은 3바이트입니다. 따라서 ‘A한B’의 두 번째 청크가 ‘한’의 두 번째 바이트부터 시작할 수도 있습니다. 각 청크를 독립 문자열처럼 디코딩하면 앞뒤가 없는 바이트가 잘못된 입력으로 처리되어 대체 문자 �가 생깁니다.

중간 조각은 decoder.decode(chunk, { stream: true })로 처리합니다. stream이 true이면 디코더는 입력이 끝났다고 판단하지 않고 완성되지 않은 문자 상태를 다음 호출까지 보존합니다. 모든 조각을 넣은 뒤에는 decoder.decode()를 인수 없이 한 번 호출합니다. 이것을 flush, 즉 남은 상태를 최종 처리한다고 말합니다. 같은 데이터 흐름에서는 반드시 같은 디코더를 사용해야 합니다.

[따라하기]

아래 내용을 chunk-decode.mjs로 저장합니다. ‘한’의 첫 바이트 뒤에서 일부러 배열을 나눕니다.

```js
const bytes = new TextEncoder().encode('A한B');
const first = bytes.slice(0, 2);
const second = bytes.slice(2);

const broken = new TextDecoder();
const wrong = broken.decode(first) + broken.decode(second);

const decoder = new TextDecoder('utf-8', { fatal: true });
let correct = '';
correct += decoder.decode(first, { stream: true });
correct += decoder.decode(second, { stream: true });
correct += decoder.decode();

console.log([...bytes].join(' '));
console.log(wrong);
console.log(correct);
```

터미널에서 실행합니다.

```text
node chunk-decode.mjs
```

예상 결과는 다음과 같습니다.

```text
65 237 149 156 66
A���B
A한B
```

첫 방식은 각 호출을 입력의 끝으로 보아 깨지고, 둘째 방식은 미완성 바이트를 보관해 원문을 복원합니다. Windows PowerShell, macOS 터미널, Linux 셸에서 명령은 같습니다. 터미널 글꼴에 따라 � 모양은 다를 수 있습니다.

[흔한 실수]

청크마다 new TextDecoder()를 만들면 이전 상태가 사라집니다. 중간 호출에서 stream 옵션을 빼도 그 호출이 끝이라고 판단해 문자가 깨질 수 있습니다. 반대로 마지막 decode()를 생략하면 끝에 미완성 바이트가 남아도 오류를 확인하지 못합니다. 패킷 하나가 문자 하나나 한 줄과 일치한다고 가정하지 마세요. 바이트 순서를 바꾸거나 같은 청크를 두 번 처리하지 않도록 순서도 관리해야 합니다.

[보안 주의]

스트리밍은 크기 제한을 없애는 기능이 아닙니다. 청크별 크기와 누적 바이트 수, 처리 시간을 제한해 메모리 고갈과 끝없는 입력을 막으세요. 서로 다른 사용자나 메시지를 한 TextDecoder에 섞지 말고 흐름마다 인스턴스를 분리한 뒤 종료 시 flush합니다. 정확한 원문이 필요한 입력은 { fatal: true }와 형식 검증을 함께 사용하세요. 인코딩은 암호화가 아니므로 비밀값을 로그에 출력하지 말고, 실습은 본인 소유의 로컬 데이터로만 진행합니다.

[직접 해볼 과제]

‘시작

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
3,945
어제
6,862
최대
16,772
전체
769,896
Copyright © 소유하신 도메인. All rights reserved.