디버깅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을 로그로 남기세요

관련 글

무료 도구 사용해 보기