개발자 도구 · URL 인코더 및 디코더
escape() 대 encodeURIComponent: JavaScript의 URL 인코딩이 어떻게 발전했는지
· 배경
자바스크립트 URL 인코딩 기록
JavaScript에는 3세대의 URL 인코딩 기능이 있으며 가장 오래된 기능은 여전히 프로덕션 코드에 숨어 있습니다. 이 게시물에서는 escape()가 무엇을 잘못하는지, ES3가 URI 함수를 추가한 이유와 !를 유지하는 이유를 설명합니다. * '( ).
레거시 로그의 %u20AC — Escape()의 확실한 지문과 이로 인한 디코딩 실패
레거시 JavaScript 파일에는 더 이상 사용되지 않는 escape() 함수를 사용하는 URL 인코딩 호출이 포함되어 있습니다. 로그 파일이나 오류 메시지의 출력에는 다른 누구도 사용하지 않는 더 이상 사용되지 않는 escape() 함수의 확실한 지문인 %u20AC 시퀀스가 포함됩니다. 이 시퀀스는 표준 URL 인코딩과 일치하지 않으며 RFC 3986 또는 WHATWG 규칙을 기반으로 구축된 디코더는 이를 인식하지 못합니다. 데이터는 최신 도구를 통해 왕복할 수 없습니다. 이는 ES3 이전에 사용되었으며 1990년대 이후 업데이트되지 않은 일반적인 코드 기호입니다.
escape() 함수는 JavaScript가 표준이나 공식 URL 인코딩 규칙을 갖기 전인 Netscape 시대에 설계되었습니다. 이는 다른 누구도 사용하지 않고 어디에도 정의된 표준이 없는 4자리 16진수 코드인 %uXXXX 표기법을 사용하여 대부분의 비ASCII 문자를 인코딩합니다. 이는 브라우저 내에서 일회성으로 사용하는 경우에는 적합했지만 URL 표준과의 호환성이 손상되어 다른 곳에서는 데이터를 디코딩할 수 없게 되었습니다.
escape() 및 unescape(): Netscape 시대 디자인 — 라틴어 1 가정, %uXXXX 발명 및 그것이 어떤 표준과도 일치하지 않는 이유
escape() 및 unescape()는 입력이 UTF-8 및 유니코드 이전의 문자 인코딩인 라틴어-1(ISO 8859-1)이라고 가정합니다. 높은 비트 Latin-1 문자에는 %XX를 사용하고 Latin-1 이외의 모든 문자에는 %uXXXX를 사용하여 각 문자를 16진수 코드로 변환합니다. 이모티콘과 같은 라틴어가 아닌 1 문자는 전혀 표현할 수 없습니다. 기능은 간단하고 빠르지만 최신 사용 사례에서는 완전히 잘못되었습니다.
두 기능 모두 표준이 존재하기 전에 JavaScript에 추가되었습니다. ES3가 1999에 적절한 URL 인코딩을 도입한 직후에는 더 이상 사용되지 않습니다. 이전 버전과의 호환성을 위해 JavaScript에 남아 있습니다. 이를 제거하면 고대 코드가 손상될 수 있습니다. 그러나 새로운 코드에서는 절대로 이를 사용해서는 안 됩니다. 그들은 유산 유물입니다.
ES3(1999)는 encodeURI 및 encodeURIComponent를 추가합니다 — UTF-8 RFC에 맞춰 정렬된 퍼센트 인코딩 2396
ES3에서는 encodeURI와 encodeURIComponent라는 두 가지 함수를 도입했습니다. 둘 다 UTF-8 퍼센트 인코딩을 수행합니다. 비ASCII 문자를 UTF-8 바이트로 변환한 다음 각 바이트를 %HH로 씁니다. 둘 다 당시 최신이었던 RFC 2396에 부합합니다. RFC 3986은 나중에 제공되었으며 인코딩 동작을 변경하지 않았습니다. 이러한 기능은 오늘날에도 여전히 표준이므로 사용해야 합니다.
encodeURI는 완전한 URI를 인코딩하기 위한 것입니다. encodeURIComponent는 쿼리 값이나 경로 세그먼트와 같은 URI 내부의 구성 요소를 인코딩하기 위한 것입니다. 그 차이는 매우 중요하며 오해하기 쉽습니다. encodeURI는 : / ? # @ = & 및 ;. encodeURIComponent는 이러한 모든 항목을 인코딩하여 더 큰 URI에 안전하게 포함할 수 있도록 합니다.
왜요! * ' ( )는 여전히 인코딩되지 않은 상태로 남아 있습니다. RFC 2396 'mark' 문자는 RFC 3986에서 이동한 후 언어에 고정됩니다.
두 함수 모두 문자, 숫자, 하이픈(-), 밑줄(_), 마침표(.), 물결표(~) 및 5개의 문장 부호 등 문자를 인코딩되지 않은 상태로 둡니다. * '( ). 표시는 예약되지 않은 "표시" 문자로 나열되는 RFC 2396에서 나왔습니다. RFC 3986은 2005에 나왔고 그 5개를 다른 범주로 옮겼지만 JavaScript는 이미 1999에서 encodeURI 및 encodeURIComponent를 고정했습니다. 그대로 두는 문자를 변경하면 기존 코드가 손상되므로 그대로 유지되었습니다.
이전 버전과의 호환성을 위해 이 5개 표시를 인코딩되지 않은 상태로 유지하기로 한 결정은 JavaScript의 인코딩이 RFC 3986 또는 WHATWG 표준과 완벽하게 일치하지 않음을 의미합니다. 실용화에는 충분히 가깝고, 지금은 바꾸는 것이 전혀 불가능합니다. 이는 API 안정성에 대한 교훈입니다. 일단 동작을 고정하면 표준이 발전하더라도 변경할 수 없습니다.
작업된 예: escape, encodeURI 및 encodeURIComponent를 통한 동일한 문자열 — 세 가지 출력 비교
"R&D(연구) = 카페's"라는 문자열을 사용합니다. escape(), encodeURI 및 encodeURIComponent를 통해 실행합니다. escape()는 "R%26D%20(research)%20%3D%20caf%E9's"를 생성하고, 인코딩되지 않은 괄호와 아포스트로피를 퍼센트 인코딩된 앰퍼샌드 및 등호와 혼합합니다. encodeURI는 "R&D%20(research)%20=%20caf%C3%A9's"를 생성하며 구조적이므로 앰퍼샌드와 등호 기호는 그대로 둡니다. encodeURIComponent는 "R%26D%20%28research%29%20%3D%20caf%C3%A9%27s"를 생성하여 괄호와 아포스트로피를 포함한 모든 것을 인코딩합니다.
동일한 문자열을 URL 인코더 및 디코더에 붙여넣고 encodeURI와 encodeURIComponent 간에 전환하여 차이점을 확인하세요. 그런 다음 escape()가 생성하는 내용을 검사합니다(경고 메시지가 표시되지만 브라우저 콘솔에서 호출할 수 있습니다). 세 가지 기능이 완전히 다른 세 가지 결과를 생성한다는 것을 즉시 알 수 있습니다.
escape()에서 마이그레이션 — 올바른 최신 함수에 대한 이전 호출 매핑 및 저장된 %uXXXX 데이터 처리
escape()를 사용하는 이전 코드를 업데이트해야 합니다. URI 구성 요소를 인코딩하는 데 escape()가 사용된 경우 이를 encodeURIComponent로 바꿉니다. 전체 URI를 인코딩하는 데 사용된 경우 encodeURI를 사용하세요. %uXXXX 시퀀스가 포함된 저장된 데이터의 경우 사용자 정의 디코더가 필요합니다. 각 %uXXXX를 유니코드 코드 포인트로 변환한 다음 코드 포인트를 문자열로 수집합니다. JavaScript에 내장된 unescape()는 %uXXXX를 읽지만 결과는 UTF-8 정확하지 않을 수 있습니다.
escape()를 교체한 후 ASCII가 아닌 문자, 구두점 및 특수 문자가 포함된 문자열로 코드를 테스트합니다. 이제 출력은 최신 도구 및 표준이 기대하는 것과 일치해야 합니다. 코드가 ES3보다 훨씬 이전 버전인 경우 다른 오래된 패턴을 사용할 수도 있습니다. 포괄적인 감사는 노력할만한 가치가 있습니다.
여기서 다루지 않는 내용 — 별도로 다루는 URL 및 URLSearchParams API
훨씬 나중에 추가된 URL 및 URLSearchParams API는 URL 구성 및 구성 요소 인코딩을 위한 더 높은 수준의 인터페이스를 제공합니다. 모든 이스케이프를 자동으로 처리하고 WHATWG URL 표준과 정확히 일치합니다. 이는 최신 JavaScript에서 프로그래밍 방식으로 URL을 구축하는 데 선호되는 방법입니다.
이 게시물에서는 고급 API가 아닌 인코딩 기능만 다룹니다. URL 및 URLSearchParams는 구조를 구문 분석하고, 구성 요소 규칙을 선택하고 결과를 직렬화하는 반면, encodeURIComponent는 제공된 문자열이 어디에 배치될지 알지 못한 채 변환합니다. 이러한 구별이 경계입니다. 값 또는 주소를 처리했는지 여부에 따라 이전 escape() 호출을 마이그레이션한 다음 별도의 리팩터링으로 주변 수동 연결을 구조화된 API로 바꾸는 것을 고려하십시오.
요점: 세 가지 기능, 하나의 살아남은 쌍 — URL 인코더 및 디코더가 최신 encodeURI 및 encodeURIComponent 동작을 나란히 표시하는 방법
최신 JavaScript 개발에서는 encodeURI 또는 encodeURIComponent를 사용해야 하며 절대로 escape()를 사용해서는 안 됩니다. 이 기능은 1999에서 표준화되었으며 그 이후로 변경되지 않았습니다. 비ASCII 문자를 UTF-8 바이트로 인코딩하고 표준 예약 문자를 올바르게 처리합니다. URL 인코더 및 디코더 도구는 두 기능을 모두 구현하고 해당 동작을 나란히 볼 수 있으므로 구성 요소에 적합한 기능을 쉽게 선택할 수 있습니다.
이전 로그나 저장된 데이터에서 %u개의 시퀀스가 발견되면 이는 escape() 출력이므로 마이그레이션해야 합니다. 패턴을 식별하면 마이그레이션이 간단해집니다. 최신 코드에서는 절대로 이를 생성해서는 안 됩니다.