JavaScript URLSearchParams 사용하기

예제 기준 · JavaScript : 브라우저 내장 URLSearchParams·URL API (별도 라이브러리 없음)

URLSearchParams는 URL의 query string을 key/value 항목으로 읽고 수정하는 API입니다. 값 조회, 같은 key의 여러 값, 추가·변경·삭제, query string 생성, URL 객체와 함께 사용하는 방법을 살펴보겠습니다.

각 절의 코드는 해당 예제의 HTML 요소가 만들어진 뒤 독립적으로 사용합니다. 버튼을 누른 결과는 pre#result에 표시합니다.

query parameter 읽기

new URLSearchParams(...)에 query string을 전달합니다. 맨 앞의 ?는 있어도 됩니다. get()은 첫 번째 값을 문자열로 반환하고, 해당 key가 없으면 null을 반환합니다. has()는 key 존재 여부를 boolean으로 알려 줍니다.

입력란 #query의 초기값은 ?name=Apple&count=2입니다. ‘query 읽기’ 버튼 #read를 누르면 name 값과 존재 여부, 없는 key인 missing의 값을 확인합니다.

function show(value) {
    document.getElementById('result').textContent = String(value);
}
document.getElementById('read').addEventListener('click', function () {
    const params = new URLSearchParams(document.getElementById('query').value);
    show('name: ' + JSON.stringify(params.get('name')) + '\nhas(name): ' + params.has('name')
        + '\nmissing: ' + JSON.stringify(params.get('missing')));
});

초기 입력값으로 버튼을 눌렀을 때의 출력입니다. 문자열과 null을 구분하기 위해 JSON.stringify()를 사용합니다.

name: "Apple"
has(name): true
missing: null

name=처럼 key는 있고 값만 비어 있으면 get('name')은 빈 문자열, has('name')은 true입니다. 숫자처럼 보이는 값도 문자열이므로 get('count')는 "2"를 반환합니다.

현재 페이지의 query parameter는 window.location.search를 그대로 전달해 읽습니다. 다음 코드는 입력란 대신 현재 주소를 사용하는 별도 예제입니다.

const params = new URLSearchParams(window.location.search);
const name = params.get('name');
const hasName = params.has('name');

console.log(name);
console.log(hasName);

URLSearchParams는 path나 hash를 분리하는 API가 아닙니다. 전체 URL을 생성자에 넣지 말고 query string만 전달하거나, 뒤에서 설명할 URL 객체의 searchParams를 사용합니다.

같은 key의 여러 값 읽기

query string에는 같은 key가 여러 번 나올 수 있습니다. get()은 첫 번째 값 하나만, getAll()은 같은 key의 모든 값을 순서대로 담은 배열을 반환합니다.

입력란 #query의 초기값은 fruit=apple&fruit=banana입니다. ‘값 비교’ 버튼 #read로 두 결과를 비교합니다.

function show(value) {
    document.getElementById('result').textContent = String(value);
}
document.getElementById('read').addEventListener('click', function () {
    const params = new URLSearchParams(document.getElementById('query').value);
    show('get: ' + JSON.stringify(params.get('fruit'))
        + '\ngetAll: ' + JSON.stringify(params.getAll('fruit')));
});
get: "apple"
getAll: ["apple","banana"]

fruit 항목을 모두 지우면 get('fruit')는 null, getAll('fruit')은 빈 배열 []을 반환합니다. 여러 선택값을 전달하는 query string에서는 getAll()로 전체 값을 읽습니다.

parameter 추가·변경·삭제

set()은 해당 key의 값을 설정하며, 같은 key가 여러 개면 하나만 남깁니다. key가 없으면 새로 만듭니다. append()는 기존 값을 유지하고 새 항목을 끝에 추가합니다. delete(key)는 해당 key의 모든 항목을 제거합니다.

초기 상태는 fruit=apple&count=1입니다. ‘fruit를 orange로 설정’ #set, ‘banana 추가’ #append, ‘fruit 삭제’ #delete, ‘초기화’ #reset 버튼으로 같은 객체의 상태를 변경합니다.

function show(value) {
    document.getElementById('result').textContent = String(value);
}
let params = new URLSearchParams('fruit=apple&count=1');
function updateState() {
    show(params.toString());
}
document.getElementById('set').addEventListener('click', function () {
    params.set('fruit', 'orange');
    updateState();
});
document.getElementById('append').addEventListener('click', function () {
    params.append('fruit', 'banana');
    updateState();
});
document.getElementById('delete').addEventListener('click', function () {
    params.delete('fruit');
    updateState();
});
document.getElementById('reset').addEventListener('click', function () {
    params = new URLSearchParams('fruit=apple&count=1');
    updateState();
});
updateState();

다음 순서로 누르면 set()과 append()의 차이가 드러납니다. count는 그대로 유지됩니다.

동작 toString() 결과
처음 또는 초기화 fruit=apple&count=1
banana 추가 fruit=apple&count=1&fruit=banana
fruit를 orange로 설정 fruit=orange&count=1
fruit 삭제 count=1

toString()은 현재 항목들을 query string으로 만듭니다. 결과 앞에 ?는 포함되지 않으며, 항목이 하나도 없으면 빈 문자열을 반환합니다.

query string 만들기

객체의 속성을 key/value로 전달하거나, [key, value] 쌍의 배열로 URLSearchParams를 만들 수 있습니다. 같은 key를 반복하려면 쌍의 배열을 사용하면 됩니다.

검색어 입력란 #keyword의 초기값은 Apple & Banana입니다. ‘query 생성’ 버튼 #create는 객체로 만든 q·page와 쌍의 배열로 만든 q·tag·tag를 각각 출력합니다.

function show(value) {
    document.getElementById('result').textContent = String(value);
}
document.getElementById('create').addEventListener('click', function () {
    const keyword = document.getElementById('keyword').value;
    const fromObject = new URLSearchParams({
        q: keyword,
        page: '1'
    });
    const fromPairs = new URLSearchParams([
        ['q', keyword],
        ['tag', 'one'],
        ['tag', 'two']
    ]);
    show('객체: ' + fromObject.toString() + '\n쌍: ' + fromPairs.toString());
});
객체: q=Apple+%26+Banana&page=1
쌍: q=Apple+%26+Banana&tag=one&tag=two

toString()은 application/x-www-form-urlencoded 규칙에 따라 인코딩합니다. 위 검색어의 공백은 +, 값 안의 &는 %26으로 바뀝니다. 한글 등도 percent-encoding되어 query string에 들어갑니다.

값을 직접 이어 붙이면 검색어 안의 &가 parameter 구분자로 해석될 수 있습니다. 객체나 set()·append()에는 인코딩하지 않은 원래 값을 전달합니다. 미리 encodeURIComponent()를 적용한 값을 다시 넣으면 %가 재인코딩될 수 있습니다.

URL 객체와 함께 사용하기

전체 주소를 다룰 때는 new URL()로 URL 객체를 만들고 url.searchParams로 query parameter를 수정합니다. path는 url.pathname, hash는 url.hash로 구분할 수 있습니다.

검색어 입력란 #keyword의 초기값은 Test입니다. ‘결과 URL 생성’ 버튼 #create를 누르면 현재 주소를 복사한 URL 객체에서 q를 설정하고 현재 주소와 결과 주소를 함께 표시합니다.

function show(value) {
    document.getElementById('result').textContent = String(value);
}
document.getElementById('create').addEventListener('click', function () {
    const url = new URL(window.location.href);
    url.searchParams.set('q', document.getElementById('keyword').value);
    show('현재: ' + window.location.href + '\n결과: ' + url.href);
});

아래 예제는 iframe 안에서 실행되므로 ‘현재’에 표시되는 주소는 이 블로그 글이 아닌 실행 예제의 주소입니다. query나 hash 없이 아래 경로로 열었을 때 초기 검색어를 사용하면 다음 문자열이 만들어집니다.

현재: https://playground.objlab.co.kr/javascript/url-search-params/url/
결과: https://playground.objlab.co.kr/javascript/url-search-params/url/?q=Test

실제 출력은 실행 예제를 연 주소를 기준으로 달라집니다. 기존 query가 있으면 q를 추가하거나 바꾸며, 다른 key와 path·hash는 유지합니다. searchParams를 수정하면 query의 인코딩 표현은 다시 직렬화될 수 있습니다.

url.href는 변경된 전체 URL 문자열입니다. 이 코드는 URL 객체만 수정하고 window.location에 값을 대입하지 않으므로 주소창 변경이나 실제 페이지 이동은 발생하지 않습니다.

주요 메서드 정리

메서드 역할
get(key) 첫 번째 값 하나. key가 없으면 null
getAll(key) 해당 key의 모든 값 배열. key가 없으면 빈 배열
has(key) key 존재 여부를 true 또는 false로 반환
set(key, value) 값 설정. 기존 동일 key 항목을 하나로 정리
append(key, value) 기존 항목을 유지하고 새 항목 추가
delete(key) 해당 key의 모든 항목 제거
toString() ? 없이 인코딩된 query string 생성

URLSearchParams를 사용하면 구분자와 값의 인코딩을 직접 조합하지 않고 query parameter를 읽고 수정할 수 있습니다. 전체 URL에서 특정 parameter만 바꿀 때는 URL 객체의 searchParams를 사용하면 path·hash와 구분해서 다루기 쉽습니다.

참고자료