URL을 문자열로 직접 조립하면 인코딩 문제나 보안 이슈가 생기기 쉽습니다. URL과 URLSearchParams API를 사용하면 안전하고 깔끔하게 URL을 다룰 수 있습니다.

URL 객체

JS
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

JS
// 생성 방법들
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 조합

JS
// 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);

특수 문자 인코딩

JS
// 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" — 전부 인코딩

실전 패턴

JS
// 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;
  }
}

쿼리 문자열을 객체로 변환

JS
// 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를 통해 인코딩해야 합니다.

댓글 로딩 중...