URL과 URLSearchParams — 쿼리 파라미터 안전하게 다루기
URL을 문자열로 직접 조립하면 인코딩 문제나 보안 이슈가 생기기 쉽습니다. URL과 URLSearchParams API를 사용하면 안전하고 깔끔하게 URL을 다룰 수 있습니다.
URL 객체
const url = new URL("https://example.com:8080/path/page?q=hello&lang=ko#section1");
console.log(url.protocol); // "https:"
console.log(url.hostname); // "example.com"
console.log(url.port); // "8080"
console.log(url.pathname); // "/path/page"
console.log(url.search); // "?q=hello&lang=ko"
console.log(url.hash); // "#section1"
console.log(url.origin); // "https://example.com:8080"
console.log(url.host); // "example.com:8080"
// 상대 URL 처리
const relative = new URL("/api/users", "https://example.com");
console.log(relative.href); // "https://example.com/api/users"
URLSearchParams
// 생성 방법들
const params1 = new URLSearchParams("q=hello&lang=ko");
const params2 = new URLSearchParams({ q: "hello", lang: "ko" });
const params3 = new URLSearchParams([["q", "hello"], ["lang", "ko"]]);
// 읽기
params1.get("q"); // "hello"
params1.has("lang"); // true
params1.getAll("tag"); // [] (없으면 빈 배열)
// 쓰기
params1.set("q", "world"); // 기존 값 교체
params1.append("tag", "js"); // 추가 (같은 키 여러 개 가능)
params1.append("tag", "web");
params1.delete("lang"); // 삭제
// 문자열로 변환
console.log(params1.toString()); // "q=world&tag=js&tag=web"
// 순회
for (const [key, value] of params1) {
console.log(`${key}: ${value}`);
}
URL과 URLSearchParams 조합
// URL에서 쿼리 파라미터 다루기
const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "자바스크립트");
url.searchParams.set("page", "1");
url.searchParams.set("sort", "date");
console.log(url.href);
// "https://api.example.com/search?q=%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8&page=1&sort=date"
// 한글이 자동으로 인코딩됨!
// fetch와 함께 사용
const response = await fetch(url);
특수 문자 인코딩
// URLSearchParams는 자동으로 인코딩
const params = new URLSearchParams();
params.set("query", "hello world & more");
params.set("special", "a=b&c=d");
console.log(params.toString());
// "query=hello+world+%26+more&special=a%3Db%26c%3Dd"
// 수동 인코딩/디코딩
encodeURIComponent("hello world"); // "hello%20world"
decodeURIComponent("hello%20world"); // "hello world"
// encodeURI vs encodeURIComponent
encodeURI("https://example.com/path?q=hello world");
// "https://example.com/path?q=hello%20world" — URL 구조 유지
encodeURIComponent("https://example.com/path?q=hello world");
// "https%3A%2F%2Fexample.com%2Fpath%3Fq%3Dhello%20world" — 전부 인코딩
실전 패턴
// 1. 현재 URL의 쿼리 파라미터 읽기
const currentParams = new URLSearchParams(window.location.search);
const page = parseInt(currentParams.get("page") || "1", 10);
// 2. 쿼리 파라미터 업데이트 (히스토리 유지)
function updateQueryParam(key, value) {
const url = new URL(window.location.href);
url.searchParams.set(key, value);
window.history.pushState({}, "", url);
}
// 3. API URL 빌더
function buildApiUrl(endpoint, params = {}) {
const url = new URL(endpoint, "https://api.example.com");
Object.entries(params).forEach(([key, value]) => {
if (value != null) {
url.searchParams.set(key, String(value));
}
});
return url.toString();
}
const apiUrl = buildApiUrl("/search", {
q: "자바스크립트",
page: 1,
limit: 20,
category: null, // null은 제외됨
});
// 4. URL 유효성 검사
function isValidURL(string) {
try {
new URL(string);
return true;
} catch {
return false;
}
}
쿼리 문자열을 객체로 변환
// URLSearchParams → 객체
function paramsToObject(searchParams) {
const obj = {};
for (const [key, value] of searchParams) {
if (obj[key]) {
// 같은 키가 여러 개면 배열로
obj[key] = Array.isArray(obj[key])
? [...obj[key], value]
: [obj[key], value];
} else {
obj[key] = value;
}
}
return obj;
}
const params = new URLSearchParams("tag=js&tag=web&page=1");
console.log(paramsToObject(params));
// { tag: ["js", "web"], page: "1" }
**기억하기 **: URL 문자열을 직접 조립하지 말고 URL/URLSearchParams API를 사용하면 인코딩 문제를 자동으로 해결합니다.
new URL()은 URL 유효성 검사에도 유용합니다. 특수 문자가 포함된 값은 반드시encodeURIComponent또는 URLSearchParams를 통해 인코딩해야 합니다.
댓글 로딩 중...