디버깅7분 분량
JavaScript에서 "URI Malformed" 오류를 해결하는 방법
JavaScript에서 흔히 발생하는 "URIError: URI malformed" 오류를 실용적인 해결책으로 진단하고 수정하는 방법을 알아봅니다.
URIError: URI Malformed 오류 이해하기
URIError: URI malformed 오류는 JavaScript에서 잘못된 percent-encoding 시퀀스가 포함된 문자열을 디코딩하려고 할 때 발생합니다. 이 오류는 decodeURI() 또는 decodeURIComponent()가 잘못 인코딩된 문자를 만났을 때 발생합니다.
흔한 원인
1. 단독으로 쓰인 퍼센트 기호
정확히 두 자리의 16진수가 뒤따르지 않는 퍼센트 기호(%)는 유효하지 않습니다. 예를 들어 %, %G, 또는 %2(불완전한 경우)는 모두 이 오류를 일으킵니다.
// 다음 코드는 URIError를 발생시킵니다
decodeURIComponent('%'); // 단독으로 쓰인 %
decodeURIComponent('%2'); // 불완전한 시퀀스
decodeURIComponent('%GH'); // 유효하지 않은 16진수
decodeURIComponent('100%'); // 16진수 없이 끝에 붙은 %
2. 유효하지 않은 UTF-8 시퀀스
percent-encoding된 바이트가 유효한 UTF-8 문자 시퀀스를 구성하지 못하면 디코더가 이를 문자열로 변환할 수 없습니다. 데이터가 손상되었거나 다른 문자 인코딩으로 인코딩된 경우에 이런 일이 발생할 수 있습니다.
3. 이중 인코딩
이중 인코딩은 이미 인코딩된 문자열을 다시 인코딩할 때 발생합니다. 예를 들어 %20(인코딩된 공백)은 %2520으로 인코딩됩니다. 원래 문자열을 디코딩하려고 하면 시퀀스가 유효하지 않을 수 있습니다.
해결 방법
해결책 1: try-catch 사용하기
function safeDecode(str) {
try {
return decodeURIComponent(str);
} catch (e) {
// 디코딩에 실패하면 원래 문자열을 반환합니다
console.warn('Failed to decode:', str, e.message);
return str;
}
}
해결책 2: 디코딩 전에 검증하기
function isValidEncodedURI(str) {
try {
decodeURIComponent(str);
return true;
} catch {
return false;
}
}
function fixMalformedURI(str) {
// 단독으로 쓰인 %를 %25(인코딩된 퍼센트)로 치환합니다
return str.replace(/%(?![0-9A-Fa-f]{2})/g, '%25');
}
해결책 3: 이중 인코딩 방지하기
function smartEncode(str) {
// 먼저 디코딩을 시도합니다 - 성공하면 해당 문자열은
// 이미 인코딩된 상태입니다
try {
const decoded = decodeURIComponent(str);
// 디코딩으로 문자열이 바뀌었다면 인코딩된 것이었습니다
if (decoded !== str) {
return str; // 이미 인코딩됨, 그대로 반환
}
} catch {
// 유효한 인코딩 문자열이 아니므로 인코딩합니다
}
return encodeURIComponent(str);
}
예방을 위한 모범 사례
- 사용자가 제공했거나 외부에서 가져온 URL을 디코딩할 때는 항상 try-catch를 사용하세요
- URL을 처리하기 전에 검증하세요
- 값을 이중으로 인코딩하지 않도록 주의하세요
- 가능하면 URL 및 URLSearchParams API를 사용하세요 -- 이 API들은 인코딩을 올바르게 처리합니다
- 인코딩 전에 쿼리 문자열 값을 정제(sanitize)하세요
- 디버깅을 위해 잘못된 URL을 로그로 남기세요