말하는 컴공감자의 텃밭

JS - 쿼리스트링 공백 -> '+' 변환 문제 본문

프론트엔드/JavaScript

JS - 쿼리스트링 공백 -> '+' 변환 문제

현콩 2025. 11. 11. 17:14
728x90

회원 가입을 마치고 사용자에게 토스트로 띄울 데이터를 담아 URL을 만들었는데 모든 공백이 '+' 로 변경되어 문제가 있었다.

url은 똑같은데 어디서는 +로 바뀌고,, 어디선 %20으로 처리되고.. 이해가 안갔는데~~

일단은 쿼리 스트링에서 값을 받아와야 하는 상황에 '감자 조아'면 '감자+조아' 이렇게 변환되어버리니, 얼른 고쳐보자.

var url = new URL(window.location.href);

 

문제의 결론은 말하자면 URL를 받아오면서 직렬화가 걸려서 공백이 '+'로 변환되고 있었다. 

 

“application/x-www-form-urlencoded”

 

 

위 스펙에 일부 규칙 때문에 공백이 '+' 로 처리 되고 있었는데~ -> 관련자료

 

애플리케이션/x-www-form-urlencoded 대 애플리케이션/json: 어떤 것을 사용해야 할까요?

API 통신의 세계를 깊이 탐구하며 application/x-www-form-urlencoded와 application/json의 주요 차이를 살펴봅니다. 요청 본문에 적합한 형식을 선택하고 데이터 교환 전략을 최적화하는 방법을 배워보세요.

apidog.com

 

일단 현재 로직의 흐름은 다음과 같다.
1. 회원가입 후 일부 데이터를 포함한 쿼리스트링을 생성한다.

2. 해당하는 쿼리 스트링을 검증해서 해당 쿼리 스트링에 토스트 메세지 관련이 있는지 확인

3. 해당하는 값이 존재할 시 사용자에게 메세지 전송
4. 사용된 쿼리 데이터는 url에서 제거한다.

 

문제는 이 흐름속에서 발생을 하게 됐다.

url에서 사용한 데이터를 가공하는 과정에서 url을 받게 되었고, 그 과정에서 직렬화가 되어버렸다.

해결하기 위해서 자동으로 직렬화 되는부분으 수동으로 바꿔주었다.

기존 공백 처리는  %20 을 사용했기에 통일하기 위함이다. 근데 공백은 왜 %20이야?-> 관련자료 

 

물론 서버나 받아오면서 단순하게 replaceAll()로 바꿔주는 방법도 있지만

직렬화 자동인게 뭔가 괘씸해서 찾아보게 되었다. 물론 +가 실제로 사용되는 경우도 대비하기 위함이긴 하다.

또한 (new URL(window.location.href) → url.searchParams.set(...) → url.toString()) 흐름이 정석이라서리..

 

그럼 이제 해결법을 보자

 

        var url = new URL(window.location.href);
        url.searchParams.delete("isTrue");
        url.searchParams.delete("forMember");

        // 공백 -> '+' 변환 문제로 수동 직렬화 추가.
        const base = url.origin + url.pathname;
        const query = Array.from(url.searchParams.entries())
            .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
            .join("&");

        history.replaceState({}, "", base + (query ? "?" + query : ""));

 

먼저 URL을 가져와주자. 저 문제 덩어리.

투플 한우가 따로없는 +++

이런식으로 href로 변환하면서 규칙이 적용되어 있다.

따라서 이 url을 우리는 원하는 부분을 수정해주자. URL의 도메인 + 경로 부분만 따로 저장해주고

쿼리에 key/value 쌍으로 순회해서 encodeURIComponent을 직접 사용해 주었다.

encodeURIComponent 는 기본적으로 공백을 %20으로 처리한다. -> 관련자료 

 

 &=? 등의 문자를 인코딩하여 URI가 제대로 해석되도록 도와줍니다.

이 함수는 주로 URI의 데이터를 안전하게 전송하기 위해 사용됩니다. 

라네요~

 

그리고 마지막으로 쪼개진 우리 쿼리 데이터가 있다면 하나하나 붙여주고 url을 만들어 줍니다.
새로고침과 뒤로가기가 되면 안되므로 history.replaceState() 를 사용해 주었다.
내부 인자로는 

  • stateObj: 히스토리 상태 객체 (보통 {} 빈 객체)
  • title: 거의 무시됨 (대부분 브라우저에서 안씀)
  • url: 교체할 주소 (현재 페이지 기준 상대·절대 가능) 

가 들어가게 된다.

이상 끝.

 

728x90
Comments