URL Encoder & Decoder (인코더 & 디코더)
URL 인코딩을 하고 풉니다. 깨진 값은 몇 번째 글자가 문제인지 짚고, 주소는 구조를 갈라 보여줍니다.
URL 인코딩이 하는 일
주소에는 아스키 글자 일부만 넣을 수 있습니다. 한글도, 공백도, & 같은 구분자도 값 안에 그대로 들어가면 안 됩니다. 퍼센트 인코딩은 그런 글자를 UTF-8 바이트로 바꾼 뒤 % 와 16진수 두 자리로 적습니다 — 한 은 세 바이트라 %ED%95%9C 가 됩니다.
암호가 아닙니다. 되돌리는 데 열쇠가 필요 없으니 감추는 용도로 쓰면 안 됩니다.
규격은 RFC 3986 입니다. 어떤 경우에도 바뀌지 않는 글자(unreserved)는 A-Z a-z 0-9 - . _ ~ 뿐입니다.
범위 셋 — 무엇을 넣느냐
같은 글자라도 어디에 넣느냐에 따라 바뀌어야 할 것이 달라집니다.
- URL — 주소 한 줄을 통째로 넣을 때.
/?&#같은 구분자는 살려 두고 한글과 공백만 바꿉니다. 구조가 그대로 남습니다 - 문자열 — 주소가 아닌 아무 글을 넣을 때. 살려 둘 구조가 없으니 구분자까지 전부 바꿉니다.
?q=뒤에 붙일 검색어가 여기입니다 - 폼 —
<form>이 보내는 방식(application/x-www-form-urlencoded). 공백이%20이 아니라+가 됩니다
https://a.com/검색?q=한 글 을 셋에 각각 넣어보면 차이가 바로 보입니다. 문자열로 인코딩하면 https%3A%2F%2Fa.com… 이 되어 더 이상 주소가 아닙니다.
셋을 "얼마나 많이 인코딩하느냐"로 줄 세울 수는 없습니다. 폼은 RFC 3986 이 아니라 URL 규격의 직렬화를 따르기 때문에 남기는 글자가 다릅니다 — 영숫자와 *-._ 뿐이라 ~ 가 빠집니다.
RFC 3986 옵션
encodeURIComponent() 는 RFC 2396 시절 규칙을 물려받아 ! ' ( ) * 다섯 글자를 남깁니다. RFC 3986 의 unreserved 에는 없는 글자들입니다.
평소에는 아무 문제가 없습니다. 문제가 되는 곳은 양쪽이 똑같은 문자열을 만들어야 하는 자리입니다 — OAuth 1.0 이나 AWS 서명은 인코딩한 문자열을 그대로 해싱하므로, 한쪽이 ( 를 남기고 다른 쪽이 %28 로 바꾸면 서명이 어긋납니다.
이 옵션을 켜면 다섯 글자도 인코딩합니다.
어디가 왜 깨졌는지 알려줍니다
브라우저의 decodeURIComponent() 는 실패하면 URIError 하나만 던집니다. 어디가 문제인지는 말해주지 않습니다.
이 도구는 두 가지를 구분해서 몇 번째 글자인지 짚습니다.
%뒤가 16진수 두 자리가 아닌 경우. 주소가 중간에서 잘렸을 때 흔합니다- 바이트는 모였는데 UTF-8 로 읽히지 않는 경우. 옛 게시판 주소에 남아 있는 EUC-KR 값이 대표적입니다 —
%C7%D1은 EUC-KR 의 "한" 이지만 UTF-8 로는 아무것도 아닙니다
두 번 인코딩된 값
%25EA%25B0%2580 처럼 % 가 다시 %25 로 감싸진 값을 자주 만납니다. 코드가 이미 인코딩된 값을 한 번 더 인코딩할 때 생깁니다.
풀었는데도 % 가 남아 있으면 그 사실을 알려주고 한 번 더 풀 수 있게 합니다. 반대로 인코드 쪽에 이미 인코딩된 값을 넣으면 인코드하기 전에 알려줍니다.
+ 는 공백일 수도, 아닐 수도
폼으로 보낸 값은 공백이 + 로 바뀌어 있습니다. 하지만 경로에 있는 C++ 의 + 는 진짜 더하기입니다.
어느 쪽인지는 값을 만든 곳만 압니다. 그래서 자동으로 정하지 않고, 값에 + 가 있을 때만 체크박스를 보여줍니다.
구조
주소나 질의 문자열을 넣으면 규격이 정한 자리로 갈라 보여줍니다 — scheme · host · port · path · query · fragment (RFC 3986 §3). 값은 전부 풀린 상태이고 한 줄씩 복사할 수 있습니다.
?q=…&page=2 처럼 질의 문자열만 잘라 온 것도 받습니다. 주소를 통째로 복사해 오지 않는 일이 오히려 더 잦기 때문입니다.
디코드에서는 query 값을 고칠 수도 있습니다. 고치면 위 칸의 주소가 그 값으로 다시 조립됩니다. 다시 인코딩되는 것은 손댄 값 하나뿐이고, 나머지 파라미터는 붙여넣은 그대로 남습니다. 전체를 URLSearchParams 에 다시 담으면 그렇게 되지 않습니다 — 그쪽은 폼과 같은 방식으로 직렬화하기 때문에 손대지 않은 a=x~y 가 a=x%7Ey 로 바뀌어 나옵니다.