배경
예를 들어,
[GET] /some/list
라는 API를 프론트 단에서 보낼 때, 검색, 페이지네이션, 필터같이 여러 기능이 필요할 때가 있을 것이다.
그럼 우리는 아래와 같이 파라미터를 보내서 해결한다.
[GET] /some/list?q=a&page=0 ...
오늘의 주인공은 바로 저 뒤 파라미터 녀석.
간혹 query parameter에 + 나 띄어쓰기를 넣으면, 다음과 같이 쿼리가 보내질 때가 있다.
만약 'eng+lish' 를 보냈다고 해보자.
?q=eng%2Blish
+가 %2B 와 같이 변했다.
이렇게 영어를 제외한 특수문자를 안전하게 전송하기 위한 방법을 인코딩이라고 한다.
인코딩
이는 웹에서 데이터를 안전하게 전송하기 위함이다. 예를 들어
الصباح رباح 라는 아랍어를 웹에서 전송하기 위해서는 ا ل ص ب ا ح ر ب ا ح 문자 각각을 보내는 것 보다, %D8%A7%D9%84%D8%B5%D8%A8%D8%A7%D8%AD%20%D8%B1%D8%A8%D8%A7%D8%AD 와 같이 정해진 규칙에 맞춰 인코딩해 보내는 것이 더 안전하다.
그리고 ?나 &같은 특수 기호들이, 기호로써 일하는지 아니면 사용자의 입력값에 있는 것인지 구분을 꼭 해야한다.
이를 위해 영어를 제외한 특수문자를 인코딩하는 규칙이 있고, 이 규칙에는 여러 종류가 있다.
오늘은 javascript 함수를 기준으로 보자.
encodeURI vs encodeURIComponent
멀리 갈 것도 없다. 당장 크롬 개발자 도구를 켜서 확인할 수 있다.
둘다 "한글" 이라는 글자를 encode했을 때, 똑같은 결과가 나오는 것을 알 수 있다.
그럼 둘의 차이는 무엇일까?
바로 띄어쓰기(space)와 +를 대하는 태도이다.
정확히는, 예약 문자를 다루는 태도가 다르다.
mdn(https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)에 따르면
encodeURI()는 완전한 URI를 형성하는데 필요한 문자는 인코딩 하지 않습니다. 또한, 예약된 목적을 가지지는 않지만 URI가 그대로 포함할 수 있는 몇 가지 문자("비예약 표식")도 인코딩 하지 않습니다.
var set1 = ";,/?:@&=+$#"; // 예약 문자
var set2 = "-_.!~*'()"; // 비예약 표식
var set3 = "ABC abc 123"; // 알파벳 및 숫자, 공백
console.log(encodeURI(set1)); // ;,/?:@&=+$#
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURI(set3)); // ABC%20abc%20123 (공백은 %20으로 인코딩)
console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24%23
console.log(encodeURIComponent(set2)); // -_.!~*'()
console.log(encodeURIComponent(set3)); // ABC%20abc%20123 (공백은 %20으로 인코딩)
URI의 Generic Syntax를 구성하기 위한 요소 말고는 변형하지 않는 친구이다.
아, API를 보낼 때는 encodeURIComponent를 써야 제대로 파라미터가 가겠구나!
라는 생각을 할 수 있겠다.
그러던 중 사소한 디테일도 발견했다.
사소한 디테일
우리의 코드가 %25ED%2595%259C%252B%25EA%25B8%2580 같은 식으로 파라미터를 보내고 있었다.
이렇게 생긴 애들은 대부분 encode를 두 번 거친 친구들이다. 어딘가 단단히 꼬인 경우인데...
오늘 있었던 일은 이랬다.
한+글 을 보내면
어찌된 영문인지 자꾸 %25ED%2595%259C%2520%25EA%25B8%2580 로 보내지는 것이다.
이 곳에는 두 개의 문제가 있었다.
1. 왜 두 번 인코딩 되는가?
2. 왜 +가 띄어쓰기로 인식되는가?
1번 두 번 인코딩 문제는 encode 함수를 전부 검색해서, axios에서도 한 번, 보내줄 때도 한 번 하는 부분을 찾아 금방 해결했지만
2번 문제는 쉽사리 해결되지 않았었는데...
한참을 찾던 중 발견했다.
navigate를 확인하자
그렇다. 종종 검색 내역이나 페이지수를 저장하려고 사용자의 URI에 keyword 정보를 넘기는 경우가 꽤 많은데,
이렇게 경우를 넘길 때 encode를 안 해주고 있었던 것!!
window.location.search 를 직접 교체해서 쓰고 있었다.
여러분은 부디 react에서 몹시 잘 제공해주는 useSearchParams hook을 예쁘게 쓰시길 바란다.
++ 2025.04.01 추가
놀랍게도, setSearchParams를 써도 encodeURI를 해버린다.
조금 원시적인 방법이지만 어쩔 수 없이 아래처럼 해야겠다.
navigate(pathname + encodeURIComponent(_query), { replace: true });
'Frontend > React, TS, node.js' 카테고리의 다른 글
[node.js] Google Spreadsheet API 사용기 #2 (0) | 2024.12.30 |
---|---|
[node.js] Google Spreadsheet API 사용기 (3) | 2024.10.25 |
[React & Typescript] i18n 적용기 (0) | 2024.10.20 |