최근 문제를 재미있게 해결한 경험이 있다. 그렇게 큰 문제는 아니었지만, 나름 뿌듯했던 순간들이 있어서 글을 쓰게 되었다. 이번 글에서는 해당 문제의 해결 과정과 URL 인코딩에 대한 간략한 설명을 다룬다.
해시(#) 이후 문자들이 잘려요
회사에서는 이미지 파일들을 업로드 하고 관리하기 위한 회사 전용 웹 서비스가 있다. 예를 들어, 행사나 새로운 서비스를 홍보하는 이미지를 업로드하면 회사 홈페이지나 어드민 페이지의 공지사항 모달창에 표시된다. 업로드를 할 때는 이미지의 노출 기간과 링크를 입력할 수 있다.
문제는 이미지 링크에 해시(#) 문자를 포함하면 '#'부터 이후 문자들까지 전부 잘려서 업로드가 된다는 것이었다. 이미지를 클릭하면 링크 페이지로 이동 후, 해당 위치로 스크롤이 되지 않는 것이다. 해당 서비스를 개발하신 분은 퇴사를 하셔서, 문제를 파악하기 위해 저장소에 있는 코드부터 살펴봤다.
처음에는 막연하게 링크를 기입하는 입력 값에 문제가 있을 것 같았다. 어떤 이유로 인해 '#'을 포함한 뒤의 문자들을 잘라내고 있다고 생각을 했다. 그래서 처음엔 사용자 입력 값을 콘솔에 찍어봤는데, 정상적으로 출력이 되었다.
다음으로 요청 헤더를 살펴봤다. 분명 값은 제대로 저장을 하는데, 헤더에는 해시를 포함한 이후 문자들이 전송되지 않았다. 그래서 인코딩에 문제가 있을 거라 생각했고, 요청을 보내는 URL의 링크 쿼리 값에 내장 함수인 encodeURIComponent()
를 사용하여 해당 문제를 해결했다.
URL 인코딩
URL은 ASCII 문자 집합만을 사용하여 인터넷 전송을 해야한다. ASCII 범위 밖의 다양한 나라의 문자나 URL에서 특별한 의미를 가지는 일부 문자를 값으로 사용하려면 유효한 ASCII 형식으로 변환해야 한다. 이를 위한 방법이 "URL 인코딩(퍼센트 인코딩)"이다. URL 인코딩은 해당 문자를 '%' 뒤에 두 개의 16진수 숫자로 대체한다.(e.g. '?' -> "%3F")
URL에서 특별한 의미를 갖는 문자들
웹 페이지의 특정 섹션을 가리키는 '#' 문자와 같이 URL에서 특별한 의미를 갖는 문자들은 인코딩 대상이 될 수 있다. 내가 겪었던 문제처럼 웹 브라우저는 URL의 '#' 문자와 이후의 내용을 서버로 전송하지 않으며, 이는 클라이언트 측에서 처리된다.
예를 들어, 사용자가 "https://example.com/search?query=book#info"라는 URL을 입력했다고 가정해보자. 이 URL을 처리할 때, 웹 브라우저는 다음과 같이 작동한다:
- 웹 브라우저는 "https://example.com/search?query=book" 부분만 서버로 전송한다.
- 서버는 해당 요청을 처리하고 응답을 클라이언트로 전송한다.
- 서버로부터 받은 웹 페이지를 렌더링하고, "#info" 프래그먼트에 따라 페이지 내의 특정 위치로 스크롤한다(만약 해당 프래그먼트 식별자가 존재한다면).
이러한 동작 방식 때문에 링크 파라미터 값에 '#' 문자가 포함되어 있다면 해당 파라미터는 '#' 문자에서 잘리게 되며, 서버로 전송되지 않았던 것이다. 이는 원치 않는 결과나 오류를 유발할 수 있기 때문에, '#'와 같은 특별한 의미를 갖는 문자는 그 의미로 사용할 것이 아니라면 URL 인코딩을 통해 안전하게 전송되어야 한다.
다음은 URL에서 특별한 의미를 갖는 문자와 그 내용이다:
- '%': 퍼센트 인코딩을 나타낸다. 예를 들어 공백은 "%20"으로 인코딩된다.
- '#': 프래그먼트 식별자(앵커)이다. URL의 '#' 뒤에 오는 내용은 브라우저에게 특정 위치로 스크롤하도록 지시하는 역할을 한다.
- '?': 쿼리 스트링의 시작을 나타낸다.
- '&': 쿼리 스트링 내에서 파라미터를 구분한다.
- '=': 쿼리 스트링 내에서 키와 값을 구분한다.
- '/': 경로를 구분하는 데 사용된다.
- ':': 프로토콜(e.g. http, https)을 나타낸 다음에 사용되거나, 포트 번호를 지정할 때 사용된다.
- '@': 주로 인증 정보를 나타낼 때 사용된다.
- '+': 보통 공백을 대체하여 사용된다.
- '[]': IPv6 주소에서 사용된다.
결론
URL 인코딩은 주로 동적 데이터를 URL 파라미터로 전송할 때 필요하다. 예를 들어, 사용자 입력을 바탕으로 API 요청을 구성할 때 사용자 입력에 특수 문자나 공백이 포함되어 있을 수 있기 때문에 인코딩이 필요하다. 이러한 인코딩 없이 특수 문자나 공백이 URL에 그대로 포함될 경우, 해당 URL은 잘못 해석될 수 있고, 예상치 못한 오류나 보안 문제를 일으킬 가능성이 있다. 따라서 URL의 일부를 전송하거나 처리할 때는 이 부분을 유의해서 코드를 작성하자.
참고
Percent-encoding(퍼센트 인코딩) - MDN
encodeURIComponent() - MDN
웹의 리소스 식별하기 - MDN
HTML URL Encoding Reference - W3Schools
HTML Uniform Resource Locators - W3Schools
퍼센트 인코딩 - 위키백과
ASCII - 위키백과
'Web' 카테고리의 다른 글
Create / Update 시 응답에 변경된 리소스를 포함해야 할까? (0) | 2023.12.17 |
---|---|
URI의 스킴(scheme)과 프로토콜(protocol) (2) | 2023.04.25 |
URI, URL 그리고 URN 이해하기 (0) | 2022.12.25 |
IE로 접속 시 알림창(alert) 띄우기 (0) | 2022.04.29 |
배포 자동화? CI/CD가 무엇일까? (0) | 2021.12.09 |