웹 애플리케이션을 개발하면서 URL의 쿼리 스트링(Query String)에서 특정 파라미터 값을 추출하거나 변경해야 하는 상황을 자주 겪어봤을 것이다.
다만 정규표현식이나 split() 함수를 조합해서 직접 파싱하다가 복잡한 인코딩 문자나 중복 키 값 때문에 예기치 못한 버그를 만들어내는 경우가 많다.
이번에는 URLSearchParams API가 정확히 무엇이고, 왜 필요한지, 그리고 실무에서 쿼리 스트링을 어떻게 안전하고 효율적으로 조작하는지 완벽하게 정리해서 소개하겠다.

 

1. URLSearchParams란 무엇인가?

URLSearchParams는 URL의 쿼리 스트링을 쉽게 다룰 수 있도록 브라우저에서 기본 제공하는 빌트인(Built-in) 객체다.
과거에는 URL에서 특정 파라미터를 가져오려면 location.search 문자열을 '?'와 '&' 기호 기준으로 split() 하거나 복잡한 정규표현식을 작성해야 했다.
하지만 이러한 방식은 한글이나 특수문자가 들어간 URL 인코딩(decodeURIComponent) 처리 시 누락이 발생하거나, 동일한 키가 여러 번 포함된 경우(예: category=tech&category=design)를 매끄럽게 처리하기 어렵다.

URLSearchParams API를 사용하면 파라미터 추가, 삭제, 수정, 읽기 작업을 순수 메서드 호출만으로 직관적으로 수행할 수 있다. 쿼리 스트링 조작 시 인코딩 문제도 자동으로 해결해 준다.

 

기존 방식 vs URLSearchParams 비교
구분기존 방식 (split / 정규표현식)URLSearchParams API
코드 가독성복잡하고 긴 구문 작성 필요단순한 메서드 호출 (get, set 등)
URL 디코딩decodeURIComponent() 직접 호출 필요파싱 시 자동 디코딩 지원
중복 키 처리별도 배열 변환 로직 직접 구현getAll() 메서드로 배열 반환
데이터 변경문자열 재조합 시 '&', '=' 처리 번거로움set(), append(), delete()로 즉시 변경

 

2. URLSearchParams 주요 메서드 한눈에 보기

URLSearchParams 객체는 쿼리 스트링 조작을 위한 강력한 메서드들을 제공한다.

  • get(name): 지정한 키의 첫 번째 값을 반환한다. 없으면 null을 반환한다.
  • getAll(name): 지정한 키에 해당하는 모든 값을 배열 형태로 반환한다.
  • set(name, value): 지정한 키의 값을 설정한다. 이미 존재하면 기존 값을 덮어쓴다.
  • append(name, value): 기존 값을 유지하면서 동일한 키로 새로운 값을 추가한다.
  • delete(name): 지정한 키와 그에 해당하는 값을 삭제한다.
  • has(name): 지정한 키가 쿼리 스트링에 존재하는지 여부를 Boolean으로 반환한다.
  • toString(): 조작된 파라미터들을 올바른 URL 쿼리 스트링 형태의 문자열로 변환한다.

 

3. 실전 예제: 쿼리 스트링 읽기 및 변경 처리

실무에서 자주 발생하는 검색 필터 및 페이지네이션 URL 조작 예제다. 잘못된 접근 방식과 URLSearchParams를 활용한 올바른 구현을 비교해보자.

✗ 잘못된 코드: split과 정규식 기반 파싱 (디코딩 오류 및 중복 키 누락)

function getQueryParam(url, key) {
  const query = url.split('?')[1];
  if (!query) return null;
  const pairs = query.split('&');
  for (let pair of pairs) {
    const [k, v] = pair.split('=');
    if (k === key) return v; // URL 디코딩 미처리 및 중복 키 데이터 유실
  }
  return null;
}

const targetUrl = "https://example.com/search?keyword=%ED%85%8C%EC%8A%A4%ED%8A%B8&tag=javascript&tag=css";
console.log(getQueryParam(targetUrl, 'keyword')); // 출력: "%ED%85%8C%EC%8A%A4%ED%8A%B8" (디코딩 안 됨)
console.log(getQueryParam(targetUrl, 'tag')); // 출력: "javascript" (뒤에 오는 'css' 유실)

 

✓ 올바른 코드: URLSearchParams API 활용

const targetUrl = "https://example.com/search?keyword=%ED%85%8C%EC%8A%A4%ED%8A%B8&tag=javascript&tag=css";
const url = new URL(targetUrl);
const params = new URLSearchParams(url.search);

// 1. 값 추출 (자동으로 한글 디코딩 완료)
console.log(params.get('keyword')); // 출력: "테스트"

// 2. 중복 키 처리 (배열로 가져오기)
console.log(params.getAll('tag')); // 출력: ["javascript", "css"]

// 3. 파라미터 변경 및 추가
params.set('page', '2'); // page=2 신규 생성
params.append('tag', 'html'); // tag=html 추가

// 4. 파라미터 삭제
params.delete('keyword');

// 5. 최종 쿼리 스트링 출력
console.log(params.toString());
// 출력 결과: "tag=javascript&tag=css&page=2&tag=html"

 

결과적으로 직접 문자열을 자르고 조작하는 과정에서 발생하는 디코딩 문제와 데이터 유실을 완전히 방지할 수 있다.

 

4. 주의사항 및 흔한 실수

URLSearchParams를 사용할 때 흔히 범하는 실수 중 하나는 생성자에 '전체 URL 문자열'을 그대로 전달하는 것이다.

✗ 잘못된 작성법: 전체 URL 문자열을 직접 전달하는 경우

// 전체 URL을 그대로 넣으면 호스트 주소와 경로까지 첫 번째 키의 일부로 잘못 인식될 위험이 있다.
const params = new URLSearchParams("https://example.com/search?page=1&sort=desc");
console.log(params.get('page')); // 동작은 하지만 올바른 사용 방식이 아님

 

✓ 올바른 작성법: URL 객체의 search 속성이나 location.search 전달

// URL 객체를 생성한 후 search 속성을 넘기거나 window.location.search를 전달한다.
const url = new URL("https://example.com/search?page=1&sort=desc");
const params = new URLSearchParams(url.search);
console.log(params.get('page')); // 출력: "1"

// 현재 브라우저 페이지의 쿼리 스트링을 다룰 때
const currentParams = new URLSearchParams(window.location.search);

 

추가로 set()과 append()의 동작 차이를 명확히 인지해야 한다. 기존 파라미터를 완전히 교체하려는 의도라면 set()을 사용하고, 검색 필터처럼 하나의 키에 여러 값을 누적해야 하는 경우에만 append()를 써야 의도치 않은 쿼리 스트링 중첩을 막을 수 있다.

 

5. 정리 및 결론

JavaScript URLSearchParams API는 웹 애플리케이션에서 쿼리 스트링을 다룰 때 발생할 수 있는 파싱 버그와 인코딩 문제 해결을 위한 필수 도구다. 직접 문자열을 자르고 연결하는 옛 방식 대신 표준 API를 활용하는 습관이 모여서 안정적이고 유지보수하기 쉬운 코드베이스를 만든다는 점을 잊지 말자. 이 글의 실전 예제 부분을 참고해 현재 프로젝트의 URL 파라미터 처리 로직을 리팩토링하면, 훨씬 깔끔하고 버그 없는 결과를 얻을 수 있을 것이다.