한국어

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

플러스 대 %20: 애플리케이션 기록/x-www-form-urlencoded

· 배경

URL 인코딩 HTML 양식 http-표준

쿼리 문자열의 더하기 기호 인코딩 공간과 URI 구문의 20%를 표시하는 양식 제출
원본 ToolAcre 벡터 일러스트레이션

양식은 공백을 +로 인코딩하지만 URI 표준은 %20이라고 하며 그 이유는 역사적입니다. 이 게시물은 초기 HTML 형식부터 오늘날의 WHATWG 정의까지의 규칙을 추적하고 그것이 결코 사라지지 않은 이유를 설명합니다.

플러스 대 %20 - 양식과 URI가 공백을 다르게 인코딩하는 이유

GET으로 제출된 HTML 양식은 쿼리 문자열에서 공백을 더하기 기호로 인코딩합니다. RFC 3986을 따르는 URL에서는 동일한 공백이 %20이 됩니다. 둘 다 다른 표준을 따르기 때문에 정확합니다. 공백이 포함된 양식 필드는 양식 인코딩에서는 이름=값+공백 포함이 되지만 RFC 3986에서는 %20이 됩니다. 데이터에 표준이 적용되는 플러스 20% 구별 표시입니다.

양식 인코딩은 HTML 2.0의 원래 양식 제출 정의인 RFC 1866(1995)의 역사적 규칙에 따라 공백에 플러스를 사용합니다. GET은 인코딩된 공백을 더하기 기호로 요청하고 리터럴 + %2B로 인코딩된 플러스를 예약합니다. 이 규칙은 일반 URI 구문이 아닌 application/x-www-form-urlencoded,에만 적용됩니다. 수십억 개의 서버 프레임워크가 이 규칙에 의존하게 되었습니다. 두 테스트 모두 명확한 차이점을 보여줍니다. 양식 모드는 플러스를 생성합니다. URI 모드는 %20을(를) 생성합니다. URL 인코더 및 디코더는 직접 비교할 수 있는 두 가지 모드를 모두 제공합니다.

초기 HTML 양식 및 GET 제출 — 양식 인코딩이 정의된 방법 및 +가 선택된 이유

RFC 1866(1995)은 공백이 플러스가 되고 리터럴 플러스가 %2B가 되는 양식 제출을 정의했습니다. 이는 애플리케이션/x-www-form-urlencoded. RFC 3986이 일반 URI 구문에 대해 %20을(를) 지정한 경우에만 적용됩니다. 두 가지 표준이 의도적으로 공존했습니다.

RFC 2396 이전 표준보다 더 엄격하게 문자 집합을 명확하게 했습니다. 이는 URI 구조를 제공하는 예약된 문자와 예약되지 않은 문자를 리터럴 데이터로 공식화했습니다. 표준 기관은 브라우저와 프록시 동작이 발전함에 따라 성문화합니다. RFC 3986은 나중에 인코딩 동작을 변경하지 않고 표기법을 명확히 하기 위해 나왔습니다. 현재의 모든 브라우저는 UTF-8 인코딩으로 표준화되어 있습니다. 제출 버튼을 통한 HTML 양식은 공백에 플러스가 포함된 application/x-www-form-urlencoded 형식을 보냅니다. 수동 URI 구성은 %20을(를) 사용합니다. 두 표준을 모두 이해하면 통합 문제를 예방할 수 있습니다.

RFC 1866 및 이후 HTML 사양 — 규칙이 기록된 위치 및 URI 구문과 어떻게 다른지

WHATWG URL 표준은 URLSearchParams.toString()이 공백에 더하기 기호가 있는 application/x-www-form-urlencoded 출력을 생성하도록 지정합니다. URL 생성자는 RFC 3986에 따라 퍼센트 인코딩됩니다. 공백이 있는 URL로 이동하는 브라우저는 %20을 인코딩합니다. GET으로 제출된 양식은 플러스를 인코딩합니다. 근본적으로 다른 도구는 다른 목적으로 사용됩니다. 수동 encodeURIComponent는 공백에 대해 %20(RFC 3986 스타일)을 제공합니다. 동일한 URL로 제출된 양식은 플러스를 보냅니다. 양식 제출을 분석하는 서버는 플러스를 기대합니다. %20을(를) 수신하면 자동 매개변수 오류가 발생합니다.

두 가지를 모두 테스트하면 사용자가 의존하는 서버 측 가정이 드러납니다. JavaScript URLSearchParams는 안전한 양식 스타일 인코딩 숨김과 복잡성을 제공합니다. URLSearchParams를 구성하고, 항목을 추가하고, toString()을 호출하여 적절한 플러스가 포함된 application/x-www-form-urlencoded을(를) 가져옵니다. 또는 encodeURIComponent를 사용하여 쿼리 문자열을 작성하십시오. RFC 3986 %20를 얻습니다. 접근 방식을 혼합하지 마십시오. 수동 plus 및 encodeURIComponent가 포함된 쿼리 문자열은 모호성을 만듭니다. 수신자는 플러스가 공백을 의미하는지 문자 그대로 플러스를 의미하는지 구별할 수 없습니다. 표준 접근 방식은 일관되게 처리됩니다.

오늘날의 URL 표준 — 자체 규칙이 있는 별도의 직렬 변환기인 애플리케이션/x-www-form-urlencoded

JSON API는 일반적으로 RFC 3986에 따라 %20을 예상하여 더하기를 공백으로 거부합니다. 플러스 전송 클라이언트는 자동으로 실패합니다. 매개변수가 사라집니다. 두 인코딩을 모두 사용하여 API를 테스트하면 어떤 표준을 허용하는지 알 수 있습니다. JavaScript의 URLSearchParams는 양식 인코딩을 처리합니다. URL 인코더 및 디코더는 RFC 3986 %20를 생성합니다.

HTML 양식 제출은 자동으로 인코딩을 처리합니다. 서버 프레임워크는 적용되는 규칙을 결정합니다. Rails, Django, PHP는 모두 자동으로 수신된 양식 데이터에서 플러스를 공백으로 처리합니다. 그러나 동일한 끝점에 대한 쿼리 문자열을 수동으로 작성하는 것은 매우 중요합니다. 업로드된 플러스는 모호함을 만듭니다. 사양 준수와 실제 서버 동작은 약간 다릅니다. 엔드포인트에서 기대하는 표준을 문서화하세요. 두 인코딩 스타일을 모두 테스트합니다. 방어 코드는 두 가지를 모두 우아하게 처리합니다.

작업된 예: 쿼리 문자열과 요청 본문으로 표시되는 동일한 양식 필드 — 한 곳에는 +가 있고 다른 곳에는 %20이 있습니다.

JavaScript URLSearchParams는 양식 인코딩을 적용합니다. 공백은 %20이 아니라 플러스가 됩니다. 새로운 URLSearchParams({q: "hello world"})는 "q=hello%20world"가 아닌 "q=hello+world"를 생성합니다. 이는 특별히 JavaScript에 내장된 역사적 애플리케이션/x-www-form-urlencoded 규칙입니다. 하지만 이 문자열을 원시 쿼리로 새 URL에 전달하면 플러스는 플러스로 유지됩니다. URLSearchParams만이 이를 공백으로 디코딩합니다. 생성자는 보이는 것에 충실합니다. 더하기 기호 차이로 인해 함수를 잘못 혼합할 때 일반적인 버그가 발생합니다.

URL 생성자와 encodeURIComponent는 다른 도구입니다. encodeURIComponent는 예약되지 않은 문자, 숫자 및 - _ 를 제외한 거의 모든 것을 인코딩합니다. ! ~ * '( ). 맥락이 없다고 가정합니다. URL 생성자는 실제 URL을 구문 분석하고 구성 요소별로 WHATWG 규칙을 적용합니다. encodeURIComponent는 "hello/world""를 "hello%2Fworld"로 바꿉니다. 새 URL은 슬래시를 경로 구분 기호로 간주합니다. 동일한 입력, 다른 출력. 조각을 연결하여 URL을 작성할 때 encodeURIComponent를 사용하십시오. 전체 또는 부분 URL의 경우 URLSearchParams 또는 URL 생성자를 사용하십시오.

수정할 수 없는 이유 — 현재 동작에 의존하는 수십 년의 서버와 클라이언트

백분율 인코딩 규칙은 RFC 1738(1994)에서 RFC 2396(1998)를 거쳐 RFC 3986(2005)로 발전했습니다. 각 세대는 모호성을 명확히 했습니다. RFC 1738는 초기 웹에서 문자 지원이 제한되었기 때문에 문자를 안전하지 않은 것으로 취급하여 보수적이었습니다. UTF-8에서 배포가 표준화되었으며 구현이 일관되었습니다. 이후 표준에서는 시스템 전체에서 안전하다고 입증되는 문자에 대한 제한을 완화했습니다. 현대적 합의: UTF-8 모든 곳에서. 표준 기관은 이전 버전과의 호환성을 강력하게 유지합니다. 문제를 해결하려면 전 세계적인 협력이 필요하지만 30년이 지나면 불가능합니다. 두 가지 표준이 의도적으로 공존합니다.

더하기 및 %20을 모두 사용하여 테스트하면 서버 가정이 드러납니다. 서버 로그에는 클라이언트가 보내는 내용이 표시됩니다. 양식은 플러스를 사용합니다. 수동 URL은 %20을 사용합니다. 상황에 따라 선택하고 API 문서를 따르세요.

여기서 다루지 않는 내용 — multipart/form-data 및 JSON 본문

두 인코딩을 모두 테스트하면 서버 동작이 드러납니다. a+b를 양방향으로 보냅니다. 많은 프로덕션 서버에서는 양식 인코딩을 기대합니다. 최신 API에는 %20이 필요합니다. 선택은 수신자의 기대에 따라 달라집니다. URLSearchParams는 양식 인코딩을 처리합니다. encodeURIComponent는 RFC 인코딩을 처리합니다.

인코딩 방법을 결합하지 마십시오. encodeURIComponent %2B로 인코딩된 후 URLSearchParams에 전달된 값은 %252B로 이중 인코딩됩니다. 한 번 디코딩하면 플러스 대신 %2B가 생성됩니다. 문자는 더하기 기호가 아닌 문자 그대로의 퍼센트-2-6 문자열이 됩니다. 빌드 프로세스의 중간 단계를 확인하세요. 인코딩은 값당 정확히 한 번만 발생합니다. 파이프라인에서 사용하는 인코딩 표준을 문서화하세요. 더하기, 공백, 앰퍼샌드를 포함한 특수 문자로 테스트합니다.

요약: 문맥에 맞는 두 가지 표준 — URL 인코더 및 디코더가 공백에 대해 %20을 사용하여 RFC 3986 형식을 제공하는 방법을 통해 어떤 표준을 보고 있는지 알 수 있습니다.

플러스 대 20 분할은 수정할 버그가 아닙니다. 서로 다른 문제를 다르게 해결하는 표준의 역사적 유물입니다. 수리하려면 전세계적인 협력이 필요하지만 30년이 지나면 불가능합니다. 표준 기관은 소급하여 웹을 중단하지 않습니다. RFC 3986, 양식 규칙, 브라우저 URL 구성에는 각각 표준과 이유가 있습니다. RFC 1866 양식 인코딩과 RFC 3986 URI 인코딩은 서로 다른 레이어를 제공합니다. 표준을 의도적으로 알고 인코딩하십시오. 실제 페이로드에 대해 테스트합니다.

상황별 인코딩을 선택하세요. 양식은 HTML 표준에 따라 플러스를 사용합니다. 수동 URI는 RFC 3986에 따라 %20을(를) 사용합니다. API는 예상할 사항을 지정합니다. 문서를 따르거나 둘 다 테스트하십시오. URL 인코더 및 디코더에 RFC 3986가 표시됩니다. 양식 인코딩이 필요합니까? URLSearchParams가 이를 수행합니다. 도구는 인코딩을 혼합하지 않습니다. 표준을 이해하면 놀라움을 예방할 수 있습니다. 레이어 간 인코딩 불일치로 인해 미묘한 매개변수 손실, 잘림, 데이터 손상이 발생합니다. 두 표준 모두 해당 영역에서 정확합니다. 의도적으로 적용하고 문서화하십시오.