한국어

개발자 도구 · URL 인코더 및 디코더

쿼리 문자열을 디코딩할 때 +가 공백이 되는 이유와 그렇지 않은 경우

· 작동 방식

URL 인코딩 자바스크립트 개발자 워크플로

다른 디코더를 통해서도 구별되는 더하기 기호 및 퍼센트 인코딩 형식
원본 ToolAcre 벡터 일러스트레이션

+가 공백을 의미하는지 여부는 호출하는 디코더에 따라 다릅니다. 이 게시물에서는 decodeURIComponent, URLSearchParams 및 서버 프레임워크가 각각 +를 처리하는 방법과 실제 플러스를 공백으로 바꾸는 것을 방지하는 방법을 설명합니다.

쿼리 문자열을 디코딩할 때 +가 공백이 되는 이유와 그렇지 않은 경우

HTML 양식 제출은 공백이 플러스가 되는 application/x-www-form-urlencoded 형식을 사용합니다. name=Alice+Smith를 수신하는 서버는 값을 추출하기 전에 각 +를 공백으로 바꿉니다. 5+3 계산과 같이 실제 플러스가 데이터에 속하면 양식 디코딩 단계 후에 5 3로 서버에 도착합니다. 이 눈에 보이지 않는 전환이 혼란의 근원입니다.

JavaScript 디코딩은 사용하는 기능에 따라 다른 결과를 생성합니다. URLSearchParams는 더하기를 공백으로 처리하여 서버 동작과 일치합니다. 그러나 decodeURIComponent는 플러스를 그대로 유지하여 문자 그대로 처리합니다. 기능 간의 이러한 비대칭성은 동일한 입력이 다르게 디코딩되는 이유입니다. 두 디코더 모두 동일한 결과를 생성할 것으로 예상한 개발자는 그렇지 않다는 사실을 발견했습니다.

비슷하게 보이는 두 가지 인코딩 — RFC 3986 퍼센트 인코딩 대 애플리케이션/x-www-form-urlencoded

두 가지 인코딩 표준은 비슷해 보이지만 다르게 작동합니다. RFC 3986은 백분율 인코딩을 정의합니다. 모든 문자는 %HH가 됩니다. 공간은 %20이 됩니다. application/x-www-form-urlencoded 표준은 약어를 추가합니다: 공백은 플러스일 수 있습니다. 둘 중 하나는 양식 컨텍스트에서 작동하지만 플러스는 선택 사항이며 해당 표준에 따라 다릅니다. 그들은 비슷한 모양을 가진 다른 도메인입니다.

decodeURIComponent 호출은 RFC 3986 디코딩에만 적용됩니다. %20은 공백으로, 플러스는 리터럴 플러스로 읽습니다. URLSearchParams는 양식 디코딩 규칙을 적용합니다. 즉, 백분율 이스케이프는 해당 문자가 되고 더하기는 공백이 됩니다. 두 기능은 서로 다른 영역에서 동일한 문제를 해결합니다. 이들을 혼합하면 실제 플러스가 사라지거나 공백이 플러스가 되어 변환에 실패하게 됩니다.

decodeURIComponent는 +를 그대로 둡니다. URLSearchParams는 이를 공백으로 바꿉니다. 두 가지 JavaScript 동작을 비교합니다.

서버 동작이 다양하여 문제가 더욱 복잡해집니다. Rails 또는 Django는 자동으로 양식 규칙을 적용합니다. 더하기는 공백이 됩니다. 그러나 URL 디코더를 사용하여 원시 쿼리 문자열을 추출하고 수동으로 디코딩하면 plus는 그대로 유지됩니다. 서로 다른 프레임워크에서 동일한 값을 처리해도 서로 다른 결과가 생성됩니다. 서버 코드는 종종 이를 암시적으로 처리하여 사용자 정의 디코더를 작성할 때까지 문제를 숨깁니다.

예: 전화번호 필드는 +1-555-0100를 국가 코드로 더하기와 함께 저장합니다. JavaScript가 더하기를 %2B로 인코딩했기 때문에 HTML 양식은 이를 %2B1-555-0100로 인코딩합니다. 서버는 이를 수신합니다. 폼디코딩을 적용하면 %2B가 플러스가 되어 값이 맞습니다. 프록시가 인코딩을 제거하는 경우 결과에 대해 decodeURIComponent를 호출하면 +1-555-0100이 생성됩니다. 각 레이어는 한 번씩 디코딩됩니다.

서버의 역할 — 일반적인 용어로 설명된 쿼리 문자열 및 요청 본문의 일반적인 프레임워크 동작

JavaScript는 encodeURIComponent를 사용하여 값을 인코딩할 수 있습니다. a+b가 주어지면 a%2Bb가 생성됩니다. 인코딩된 문자열이 서버나 양식 인식 디코더에 도달하면 %2B는 플러스로 디코딩되고 결과는 정확합니다. 대신 양식 규칙을 사용하여 인코딩하면 공백은 플러스가 되고 실제 플러스는 %2B가 됩니다. 어느 쪽이든 인코딩은 %2Bb를 생성합니다. 해석은 적용되는 디코딩 규칙에 따라 달라집니다.

왕복 테스트: a+b로 시작합니다. %2Bb를 얻으려면 encodeURIComponent로 인코딩하세요. decodeURIComponent를 사용하여 a%2Bb를 디코딩하고 a+b를 복구합니다. a+b를 URLSearchParams에 전달합니다. 더하기를 공백으로 처리하여 b를 생성합니다. a%2Bb를 URLSearchParams에 전달하여 a+b를 다시 가져옵니다. 두 가지 방식으로 디코딩된 동일한 입력은 사용하는 디코더에 따라 다른 출력을 생성합니다.

작동된 예: 두 디코더를 모두 통한 'a+b' 및 'a%2Bb' — 테이블의 4개 결과

일반적인 실수가 바로 이어집니다. 개발자는 decodeURIComponent로 디코딩하고 실수 플러스가 포함된 수신 양식 데이터가 중단되는 이유를 궁금해합니다. URLSearchParams를 사용했어야 합니다. 반대로 누군가는 decodeURIComponent를 사용해야 할 때 URLSearchParams를 사용하고 모든 리터럴 플러스가 사라집니다. 두 번 인코딩하면 %252B가 생성되므로 올바르게 디코딩하려면 일치하는 인코더-디코더 쌍이 필요합니다.

또 다른 실수는 인코딩 없이 ?q=value로 쿼리 문자열을 직접 구성하는 것입니다. 값에 앰퍼샌드나 등호가 있으면 새 매개변수가 자동으로 생성됩니다. 브라우저는 연결을 추측하지 않습니다. 결과를 적절하게 형성된 것으로 처리합니다. encodeURIComponent를 사용한 의도적인 인코딩만이 이를 방지합니다. URL 인코더 및 디코더는 세 가지 기능을 모두 표시하여 각각이 생성하는 기능을 보여줍니다.

일반적인 실수 - 두 번 디코딩하거나 경로 세그먼트에서 공백을 +로 인코딩

양식 인코딩 규칙은 HTTP 요청 본문 Content-Type 헤더를 설명하므로 application/x-www-form-urlencoded이라고 합니다. 파일 업로드가 없는 HTML 양식은 본문을 이 형식으로 보냅니다. URL의 쿼리 문자열도 이 규칙을 사용하지만 기술적으로 공식적인 인코딩 표준은 없습니다. URL 사양은 쿼리를 불투명하게 처리합니다. 더하기 의미는 필수가 아닙니다. 그러나 웹 애플리케이션에서 플러스는 일반적으로 공간을 의미합니다.

올바른 동작을 보장하려면 의도적으로 인코딩하고 일치 함수를 사용하여 디코딩합니다. encodeURIComponent로 인코딩한 경우 decodeURIComponent로 디코딩합니다. HTML 양식 데이터를 읽거나 양식 형식의 요청 본문을 읽는 경우 URLSearchParams를 사용하세요. 절대 겉모습으로 추측하지 마세요. a+b와 같은 문자열은 모호합니다. 디코더는 서로 바꿔 사용할 수 없습니다.

여기서 다루지 않는 내용 — 다중 부분 양식 데이터 및 JSON 요청 본문

다중 부분 양식 데이터, JSON 요청 본문 및 기타 표준에는 별도의 인코딩 규칙이 있습니다. JSON은 공백이나 백분율 인코딩에 더하기를 사용하지 않습니다. 유니코드 이스케이프를 사용합니다. 멀티파트는 다른 경계를 사용합니다. 이 문서에서는 쿼리 문자열과 양식으로 인코딩된 본문만 다룹니다. 여기에 플러스 모호성이 나타나기 때문입니다. 항상 Content-Type 헤더와 이를 정의하는 RFC를 확인하세요.

쿼리 값에 속하는 경우 리터럴 플러스를 항상 %2B로 인코딩합니다. URL 인코더 및 디코더는 %20이 되는 공백과 별도로 구성 요소 모드에서 플러스가 %2B로 보호되는 방법을 보여줍니다. 각 모드를 통해 a+b 및 a%2Bb를 전달한 후 결과를 검토합니다. 이 비교는 동일한 입력이 다르게 디코딩되는 이유를 보여줍니다. 차이점은 서로 다른 두 표준의 올바른 동작입니다.

요약: 항상 리터럴 더하기를 %2B로 인코딩합니다. URL 인코더 및 디코더가 값이 백분율로 인코딩된 쿼리 값으로 표시되는 방식을 보여줍니다.

요약: 쿼리 문자열의 더하기는 %2B로 보호하는 인코딩에서 나온 것이 아닌 한 리터럴 더하기가 아니라 공백에 대한 단축 인코딩 형식입니다. 잘못된 디코더는 해당 보호 기능을 잃습니다. URLSearchParams는 최신 JavaScript에서 가장 안전합니다. 이는 양식 인코딩을 처리하고 명명된 매개변수 액세스를 제공합니다. 원시 문자열의 경우 encodeURIComponent는 모든 것을 보호합니다. decodeURIComponent는 %20 및 퍼센트를 해석하지만 더하기는 문자 그대로 처리합니다.

테스트해 보세요. ?x=a+b를 직접 빌드하고 URL 인코더 및 디코더에 붙여넣으세요. 이를 검사하고 URLSearchParams가 값 a b를 사용하여 매개변수 x로 분할하는 것을 확인하세요. ?x=a%2Bb를 붙여넣고 a+b 값을 확인하세요. encodeURIComponent를 사용하여 URL을 작성하고 비교하십시오. 시각적 확인을 통해 규칙이 명확해집니다. 양식 규칙은 플러스를 사용하고, 백분율 인코딩은 %20을 사용하며, 이를 혼합하면 플러스가 공간으로 사라지는 이유입니다.