이번에 admin-toggle-page 과제를 기회로 URLSearchParams에 대해 알아보게 되었습니다.
구현해야 하는 기능들에는 필터링(filter), 페이지네이션(pagination), 토글(toggle)이며 모든 기능은 뒤로가기가 지원되어야 하며 새로고침 시에도 데이터가 유지되어야 했습니다.
위 기능들의 공통점은 쿼리 스트링을 활용해야 한다는 것이었으며, 쿼리 스트링으로는 검색(search)과 정렬(sort) 등 다양한 용도로도 사용되므로 한 번 정리하고 넘어가는 것이 좋을 것 같아 글로 남기게 되었습니다.
쿼리스트링은 검색 파라미터(search parameters)라고 불립니다.
URL에서 경로(pathname) 바로 다음에 나오는 ? 기호로 시작하는 문자열입니다. 보통 웹 서버에서는 URL의 쿼리 스트링을 분석하여 요청한 리소스를 응답하기 전에 다양한 추가 작업을 수행할 수 있습니다.
?key1=value1&key2=value2
쿼리 스트링은 위의 형태로 표현할 수 있으며 여러 개의 키와 값의 쌍을 & 기호로 구분하여 매개변수를 명시할 수 있습니다. 매개변수의 개수가 많아질수록 가독성이 떨어지기 때문에 인코딩에도 신경을 써줘야 합니다.
?key=value1&key=value2
URL 명세서에 따르면 쿼리 스트링은 위와 같이 동일한 키에 여러 개의 값을 할당하는 것도 허용하는데 경계 조건을 잘 고려하지 않으면 버그로 이어질 우려가 있으므로 주의해야 합니다.
URL은 Uniform Resource Locator의 약자입니다.웹에서 사용되는 주소를 의미하며 미리 약속된 규약이 있고 공식적으로 문서화가 되어 있습니다. 모든 세대에 각각 유일한 주소가 있어 우편과 택배가 정확히 배달이 올 수 있는 것처럼 인터넷에도 브라우저(browser)가 웹 사이트에 방문할 수 있도록 이미지나 오디오, 비디오와 같은 모든 자원(resource)에 유일한 주소가 부여되어 있어야 합니다.
노드에서는 url 모듈을 사용하여 사이트 주소 정보를 url 객체로 만들 수 있습니다 :
예시의 주소를 기준으로 위는 URL 방식, 아래는 WHATWG 방식입니다.
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ href │
├──────────┬──┬─────────────────────┬────────────────────────┬───────────────────────────┬───────┤
│ protocol │ │ auth │ host │ path │ hash │
│ │ │ ├─────────────────┬──────┼──────────┬────────────────┤ │
│ │ │ │ hostname │ port │ pathname │ search │ │
│ │ │ │ │ │ ├─┬──────────────┤ │
│ │ │ │ │ │ │ │ query │ │
" https: // user : pass @ sub.example.com : 8080 /p/a/t/h ? query=string #hash "
│ │ │ │ │ hostname │ port │ │ │ │
│ │ │ │ ├─────────────────┴──────┤ │ │ │
│ protocol │ │ username │ password │ host │ │ │ │
├──────────┴──┼──────────┴──────────┼────────────────────────┤ │ │ │
│ origin │ │ origin │ pathname │ search │ hash │
├─────────────┴─────────────────────┴────────────────────────┴──────────┴────────────────┴───────┤
│ href │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
url 모듈을 이용해 주소 문자열을 객체로 만들면 문자열 안에 있던 각각의 정보를 나누어 그 객체의 속성으로 보관할 수 있습니다.
호스트 네임(hostname)은 사람이 읽기 쉬운 도메인 네임(domain name)이 될 수도 있고, 127.0.0.1처럼 컴퓨터가 바로 이해할 수 있는 형태인 IP 주소가 될 수도 있습니다.
경로명(pathname)은 웹 서버의 자체적인 라우팅(routing)을 통해서 논리적인 위치를 사용할 수 있습니다.
const url = new URL('https://user:pass@ sub.example.com:8080/p/a/t/h?query=string#hash');
url.href; // https://user:pass@ sub.example.com:8080/p/a/t/h?query=string#hash
url.origin; // https://user:pass@ sub.example.com
url.protocol; // https:
url.username; // user
url.password; // pass
url.host; // www.user:pass@ sub.example.com:8080
url.hostname; // www.user:pass@ sub.example.com
url.port; // 8080
url.search; // query=string
url.hash; // hash
url.searchParams; // {}
출처(origin)는 브라우저에서 보안 상의 이유로 다른 출처로의 HTTP 요청을 제한하는 CORS(Cross-Origin Resource Sharing)의 토대가 되는 개념이니 참고 바랍니다.
URL의 제일 마지막 부분은 앵커(anchor), 해시(hash), 조각(fragment) 등 다소 다양한 이름으로 불리며 리소스 내에서 특정 부분을 나타내는데 사용합니다. 긴 컨텐츠의 목차를 구현할 때 유용하게 사용될 수 있습니다.
예를 들어, 목차 내의 해시가 붙어 있는 링크를 클릭하면 브라우저가 웹 페이지의 특정 섹션으로 자동으로 스크롤되게 할 수 있습니다. 이 부분은 클라이언트에서만 의미가 있는 부분이기 때문에 웹 서버로는 전송되지 않습니다.
URL API에서 제공하는 주소창의 경로를 다룰 수 있는 브라우저의 내장 객체입니다.
이전에는 쿼리 스트링을 일반 문자열로 다루는 경우가 많아서 다루기 까다로웠지만 현재는 URLSearchParams를 사용하여 좀 더 안전하게 쿼리 스트링을 다룰 수 있게 되었다고 합니다.
URLSearchParams.toString()
URL에 사용하기에 적합한 쿼리 문자열이 포함된 문자열을 반환합니다.
const searchParams = new URLSearchParams([
["mode", "dark"],
["page", 1],
]);
searchParams.toString(); // 'mode=dark&page=1'
URLSearchParams.append()
지정된 키/값 쌍을 새 검색 매개변수로 추가합니다.
const searchParams = new URLSearchParams();
searchParams.append("mode", "dark");
searchParams.append("page", 1);
searchParams.append("sort", "email");
searchParams.append("sort", "date");
searchParams.toString(); // 'mode=dark&page=1&sort=email&sort=date'
URLSearchParams.set()
지정된 검색 매개변수와 연관된 값을 지정된 값으로 설정합니다. 값이 여러 개인 경우 나머지는 삭제됩니다.
const searchParams = new URLSearchParams();
searchParams.set("mode", "dark");
searchParams.set("page", 1);
searchParams.set("sort", "email");
searchParams.set("sort", "date");
searchParams.toString(); // 'mode=dark&page=1&sort=date'
URLSearchParams.delete()
모든 검색 매개변수 목록에서 이름 및 선택적 값과 일치하는 검색 매개변수를 삭제합니다.
searchParams.delete("sort");
searchParams.toString(); // 'mode=dark&page=1'
URLSearchParams.get()
지정된 검색 매개변수와 연관된 첫 번째 값을 반환합니다.
URLSearchParams.getAll()
지정된 검색 매개변수와 연관된 모든 값을 반환합니다.
searchParams.get("mode"); // 'dark
searchParams.getAll("mode"); // [ 'dark' ]
searchParams.get("sort"); // 'email'
searchParams.getAll("sort"); // [ 'email', 'date' ]
URLSearchParams.has()
지정된 매개변수 또는 매개변수와 값 쌍이 존재하는지 여부를 나타내는 boolean 값을 반환합니다.
searchParams.has("page"); // true
searchParams.has("x"); // false
객체에 저장되어 있는 파라미터는 모두 for...of 문으로 순회할 수 있습니다.
for (const [key, value] of searchParams) {
console.log(`${key}: ${value}`);
}
URLSearchParams.sort()
모든 키/값 쌍이 있는 경우 해당 키를 기준으로 정렬합니다.
URLSearchParams.forEach()
콜백 함수를 통해 이 개체에 포함된 모든 값을 반복할 수 있습니다.
URLSearchParams.entries()
iterator쿼리 문자열에 나타나는 것과 동일한 순서로 이 객체에 포함된 모든 키/값 쌍을 통해 허용되는 반복을 반환합니다.
URLSearchParams.keys()
iterator이 객체에 포함된 키/값 쌍의 모든 키를 통해 허용되는 반복을 반환합니다.
URLSearchParams.values()
iterator이 객체에 포함된 키/값 쌍의 모든 값을 통해 허용되는 반복을 반환합니다.
URLSearchParams 객체의 생성자는 아래와 같은 형태의 값을 인자로 받을 수 있습니다.
new URLSearchParams([
["mode", "dark"],
["page", 1],
["draft", false],
["sort", "email"],
["sort", "date"],
]);
new URLSearchParams("?mode=dark&page=1&draft=false&sort=email&sort=date");
new URLSearchParams();
기존의 URL의 쿼리 스트링을 접근하거나 조작하고 싶을 때 두 가지를 함께 사용할 수 있습니다.
URL 객체의 search 속성에는 쿼리 스트링이 문자열로 searchParams 속성에는 쿼리 스트링이 URLSearchParams 객체로 저장이 되어 있습니다. URL 객체의 searchParams 속성에 접근하여 아래와 같이 쿼리 스트링을 간편하게 조작할 수 있습니다.
const url = new URL("https://example.org:8080/foo/bar?q=baz#bang");
url.search; // '?q=baz'
const searchParams = url.searchParams; // URLSearchParams {size: 1}
searchParams.get("q"); // 'baz'
searchParams.set("q", "updated");
searchParams.append("r", 2);
searchParams.append("r", false);
url.toString(); // 'https://example.org:8080/foo/bar?q=updated&r=2&r=false#bang'
한 가지 범하기 쉬운 실수는 새로운 URLSearchParams 객체를 바로 URL 객체의 searchParams 속성에 할당하는 것입니다. 아래가 잘못된 사례의 코드입니다.
const url = new URL("https://example.org:8080/foo/bar?q=baz#bang");
url.searchParams = new URLSearchParams("q=updated&r=2&r=false");
url.toString(); // 'https://example.org:8080/foo/bar?q=baz#bang'
새로운 쿼리 스트링이 반영되지 않은 이유는 URL 객체의 searchParams 속성이 읽기 전용이기 때문입니다.
따라서 URL 객체의 searchParams 속성을 읽은 후에 매개변수를 조작할 수는 있지만 아예 새로운 쿼리 스트링으로 대체할 수는 없습니다.
대신 URL 객체의 search 속성은 쓰기가 가능하기 때문에 아래와 같이 URLSearchParams 객체를 문자열로 변환한 후에 URL 객체 search 속성에 할당해주어야 쿼리 스트링을 대체할 수 있습니다.
const url = new URL("https://example.org:8080/foo/bar?q=baz#bang");
url.search = new URLSearchParams("q=updated&r=2&r=false").toString();
url.toString(); // 'https://example.org:8080/foo/bar?q=updated&r=2&r=false#bang'
project
#1.Admin-Toggle-Page
20231204 - 20231208: 과제 진행
20231209 - 20231211: code review & develop
20231211 - 20231212: URLSearchParams 관련 자료 검색 및 블로그 작성
gitHub Link: https://github.com/55555-Jyeon/admin-toggle-page
references
[URL]
https://developer.mozilla.org/en-US/docs/Web/API/URL
https://runebook.dev/ko/docs/node/url
[URLSearchParams]
https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
https://www.zerocho.com/category/HTML&DOM/post/5b3ae84fb3dabd001b53b9ab