URL 정규화 도구
URL을 정규화: 스킴과 호스트를 소문자로, 기본 포트 제거, 쿼리 파라미터 정렬, 빈 프래그먼트 제거
URL
정규화됨
URL 정규화 도구란?
"같은" 두 URL이 대소문자나 쿼리 순서 때문에 비교에서 다르게 나오는 건 한나절을 잡아먹는 버그 중 하나입니다. HTTPS://Example.com/page 와 https://example.com/page 는 같은 리소스를 가리키지만 문자열 비교는 다르다고 합니다. 정규화 도구는 URL을 받아서 RFC 3986 §6 과 WHATWG URL Standard 에 따라 정규형을 만들어 주므로, 같은 의미의 두 URL이 같은 문자열로 나옵니다.
수행하는 정규화는 지루하지만 중요한 것들입니다: 스킴과 호스트를 소문자로(RFC 3986 §6.2.2.1 에 따라 대소문자 무시), 기본 포트 제거(:443 on https, :80 on http), 퍼센트 인코딩된 비예약 문자 디코딩(%41 → A), 쿼리 파라미터를 키 기준 알파벳 정렬, 빈 프래그먼트(# 뒤에 아무것도 없는 경우) 제거, . / .. 경로 세그먼트 정리. 출력 JSON에는 정규화된 URL, 원본 URL, 그리고 어떤 부분이 어떻게 다시 쓰였는지 정확히 나열한 changes 배열이 들어 있어, 달라 보이던 두 URL이 실제로는 왜 같은지 한눈에 볼 수 있습니다.
모든 작업은 표준 URL API 와 URLSearchParams 를 사용해 브라우저 안에서 처리됩니다 — 서버 전송도, 로그도 없습니다. 입력이 이미 정규형이라면 changes 배열이 비어 있고 그게 답입니다: 손댈 게 없습니다. 사이트맵을 게시하거나 <link rel="canonical"> 을 설정하기 전에 잠깐 확인하기 좋습니다.
URL 정규화 도구 사용법
세 단계. 각 단계는 이 페이지의 버튼 하나에 대응됩니다.
URL을 붙여넣거나 샘플 불러오기
왼쪽 패널에 URL을 넣으세요. 샘플을 누르면 현실적으로 지저분한 URL이 로드됩니다 — 스킴과 호스트가 대문자, 기본 포트 포함, 쿼리 순서가 뒤섞임, 퍼센트 인코딩된 공백, 빈 프래그먼트. 예시 URL:
HTTPS://API.Shop.Example.com:443/v1/orders/?status=active&customer=Ava%20Chen&page=2#국제화 도메인 이름(IDN)은 URL 생성자에 의해 Punycode로 변환됩니다 — 그게 실제로 네트워크에서 전송되는 형태이며, URI 정규화 규칙을 따릅니다. 사용자 정보(user:pass@host)가 있다면 보존됩니다.
출력 읽기
오른쪽 패널은 세 개의 필드를 가진 JSON을 보여줍니다: normalized(정규 URL), original(붙여넣은 값, 트림됨), 그리고 changes — 모든 재작성을 나열한 { rule, from, to } 항목들의 배열. changes 가 비어 있으면 URL은 이미 정규형이었습니다.
복사 또는 다운로드
복사를 누르면 JSON이 클립보드로 가고, 다운로드를 누르면 .json 파일로 저장됩니다. 압축은 JSON을 한 줄로 만듭니다. 입력 패널에서 지우기를 눌러 다시 시작할 수 있습니다.
실제로 쓰게 되는 순간
캐시 키와 분석 중복 제거
분석 대시보드는 Example.com/page 와 example.com/page 를 별개의 행으로 봅니다. CDN 캐시도 마찬가지입니다. 들어올 때 정규화하면 중복이 사라집니다. URL 단축기나 북마크 중복 제거기를 만들 때도 같은 요령으로, 정규화된 형태를 조회 키로 저장하세요.
SEO를 위한 정규 URL
검색 엔진은 같은 페이지가 여러 URL로 도달 가능할 때 중복 콘텐츠로 페널티를 줍니다. <link rel="canonical"> 태그와 sitemap.xml URL은 하나의 정규화된 형태에 맞춰져야 합니다. 구글의 정규화 가이드가 규칙을 설명하고, 이 도구는 그걸 손으로 가장 빠르게 적용하는 방법입니다.
두 URL이 같은지 비교
리다이렉트 루프 탐지기를 작성하거나 웹훅을 테스트 중일 때. 두 URL은 정규형이 일치하면 "같은" 것입니다. 정규화 후에 문자열을 비교하세요 — URL.toString() 기반의 자체 동등성 함수를 만들지 마세요. 그건 쿼리 파라미터를 정렬하지도, 기본 포트를 떨어뜨리지도 않습니다.
저장이나 표시 전에 URL 정리
사용자가 폼에 HTTPS://www.SHOP.com:443/cart/?b=2&a=1# 를 붙여넣었습니다. 그걸 DB에 저장하고 싶지 않고, 이메일로 보내는 건 더더욱 싫겠죠. 먼저 정규화한 다음 깨끗한 형태를 저장하세요. 사용자에게 보이는 URL이 예측 가능해집니다.
자주 묻는 질문
제 URL이 이미 정규형이라면?
normalized 와 original 에 같은 URL이 보이고 changes 배열은 비어 있을 것입니다("changes": []). 그게 답입니다 — 다시 쓸 게 없었습니다. 이 경우 페이지가 예외를 던지거나 오류를 표시하지 않습니다.
루트의 끝 슬래시 제거 외에 경로를 건드리나요?
대부분 건드리지 않습니다. . 와 .. 경로 세그먼트는 해석됩니다(URL 생성자가 자동으로 처리합니다 — RFC 3986 §5.2.4 는 이를 "remove dot segments" 라고 부릅니다). 끝 슬래시는 경로가 / 하나일 때만 제거됩니다. /v1/orders/ 는 그대로 /v1/orders/ 로 둡니다 — RFC 3986 은 끝 슬래시가 의미를 가질 수 있다고 말하기 때문입니다. 서버 프레임워크에 따라 다른 라우트로 취급되기도 합니다.
왜 쿼리 파라미터가 정렬되나요? 순서가 중요한데요.
RFC 3986 에서 쿼리 순서는 의미적으로 중요하지 않습니다 — ?a=1&b=2 와 ?b=2&a=1 은 URL 수준에서 동등합니다. 알파벳순 정렬은 안정적인 정규형을 주어, 동등한 두 URL이 바이트 단위로 일치하게 합니다. 애플리케이션이 실제로 파라미터 순서에 의존한다면(그래선 안 되지만 레거시 시스템은 그렇게 하기도 합니다), 이 정규화 도구가 그 가정을 깨뜨립니다 — 순서를 따지는 서버에 보내는 URL은 정규화하지 마세요.
정규화 후에 %20 이 가끔 + 가 되는 이유는?
%20 과 + 모두 쿼리 문자열 내에서는 공백을 의미합니다(application/x-www-form-urlencoded 규칙으로, URLSearchParams 가 직렬화에 사용합니다). URLSearchParams 객체가 쿼리를 재직렬화하면 + 를 사용합니다. 표준을 지키는 어떤 URL 파서에서도 의미적으로 동일합니다. 서버가 둘을 다르게 취급한다면 그건 서버 버그입니다.
café.example 같은 국제화 도메인은 어떻게 되나요?
URL 생성자가 호스트를 Punycode로 변환합니다 — caf%C3%A9.example 가 xn--caf-dma.example 가 됩니다. DNS로 실제 전송되는 형태이며, RFC 3987 / WHATWG 사양이 정한 것입니다. 위키피디아의 URI 정규화 문서가 IDN 처리를 자세히 설명합니다.
인증 정보가 포함된 URL(user:pass@host)도 안전한가요?
파싱은 전적으로 브라우저 안에서 일어나며 어디로도 전송되지 않습니다. userinfo는 정규화 과정에서 보존됩니다. 애초에 URL에 인증 정보를 넣어야 하느냐는 다른 문제입니다 — 대부분의 브라우저와 HTTP 클라이언트는 보안 위험 때문에 userinfo를 제거하거나 경고하며, 보통은 Authorization 헤더가 더 낫습니다.
중복된 쿼리 파라미터를 제거하나요?
아니요. ?tag=red&tag=red 는 ?tag=red&tag=red 그대로 둡니다. 반복 키는 의미가 있을 수 있고(배열용으로 쓰는 API가 있습니다), 중복을 없애면 의미가 바뀝니다. 정렬은 안정 정렬이므로 같은 키 안에서는 원래 순서가 유지됩니다.
다른 URL & JSON 도구
정규화는 한 가지 작업에 불과합니다. 자연스럽게 함께 쓰면 좋은 도구들: