# URL(SearchParams), encodeURI(Component)

> 특정 리소스를 식별하고 싶은 경우에는 `Path Variable` / 정렬이나 필터링이 필요한 경우에는 `Query Parameter`를 사용하는 것이 권장된다.

### `Path Variable` vs. `Query Parameter`

* Path Variable로 전달된 값을 이용해 리소스를 식별할 수 없다면 404가 발생할 것이고, Query Parameter를 이용해 조회를 한 경우에는 빈(empty) 값을 반환하게 될 것이다.
* 필터링을 수행할 때 404가 발생하는 것은 부적절하므로 정렬이나 필터링을 수행해야 하는 경우에 Query Parameter를 사용하는 것이다.

#### `req.params` -> Path Variable

```typescript
/:id/:name?query_1=...&query_2=...
   -> req.params = { id: ..., name: ... }
```

#### `req.query` -> Query Parameter

```typescript
/:id/:name?query_1=...&query_2=... 
  -> req.query = { query_1: ..., query_2: ... }
```

### 퍼센트 인코딩 (Percent Encoding)

퍼센트 인코딩 규약은 RFC 3986에 정의되어 있으며 명세에 따르면 URL에서 중요하게 사용되는 **예약(reserved) 문자**가 있고, 인코딩이 필요하지 않은 **비예약(unreserved) 문자**가 존재한다.

**RFC 3986 section 2.2 Reserved Characters**

예약 문자는 문법적인 의미를 가지고 있으므로 해당 문법적 의미로 사용되지 않게 하려면 반드시 인코딩해야 한다.

`!`, `*`, `'`, `(`, `)`, `;`, `:`, `@`, `&`, `=`, `+`, `$`, `,`, `/`, `?`, `#`, `[`, `]`

여기에 더해 안전하지 않다고 여겨지는 문자들 역시 인코딩을 수행해 주어야 한다.

&#x20;, `"`, `<`, `>`, `%`, `{`, `}`, `|`, `\`, `^`, `` ` ``

**RFC 3986 section 2.3 Unreserved Characters**

`[a-zA-Z]`, `[0-9]`, `-`, `.`, `_`, `~`

### `URL`, `URLSearchParams`

```typescript
URL === window.URL; // true

new URL(url, [base]);

const url = new URL("https://example.com?q=1");
url.searchParams.get("q"); // "1"

new URLSearchParams("q=1").get("q"); // "1"
```

RFC 3986 명세에 따라 자동으로 인코딩하여 변환해주며, 가장 최근에 도입된 API이다.

### `encodeURI` vs. `encodeURIComponent`

```typescript
const set = "-.!~*'()"; // Unreserved Marks

encodeURI(set);          // "-.!~*'()"
encodeURIComponent(set); // "-.!~*'()"
```

두 함수 모두 RFC 2396 명세 기준으로 비예약(unreserved) 문자로 취급되는 `-`, `.`, `!`, `~`, `*`, `'`, `(`, `)`는 인코딩하지 않는다.

```typescript
const set = ";/?:@&=+$,#"; // Reserved Characters

encodeURI(set);          // ";/?:@&=+$,#"
encodeURIComponent(set); // "%3B%2C%2F%3F%3A%40%26%3D%2B%24%23"
```

다만 `encodeURI`는 URL에 사용할 수 없는 문자만 인코딩하지만, `encodeURIComponent`는 예약 문자까지 모두 인코딩하는 차이가 존재한다.

```typescript
`?q=${encodeURI("a&b")}`;          // "?q=a&b"
`?q=${encodeURIComponent("a&b")}`; // "?q=a%26b"
```

따라서 Query Parameter에 적용하는 경우에는 `encodeURIComponent`를 사용하는 것이 더 올바른 접근이다.

### 정리

`URL`, `URLSearchParams`는 모두 RFC 3986을 기반으로 동작하지만, `encodeURI`, `encodeURIComponent` 함수는 보다 이전 버전인 RFC 2396을 기반으로 하므로 기본적으로는 `URL`, `URLSearchParams`를 고려하는 것이 좋다.

```typescript
const url = new URL("https://example.com?q=1+2");
url.search; // "?q=1+2"
url.searchParams.get("q"); // "1 2"

new URLSearchParams("q=1+2").get("q"); // "1 2"
```

다만 `URLSearchParams`은 **`+` 기호를 공백(space)로 해석**하기 때문에 문제를 발생시킬 수 있으므로 보다 안전하게 사용하기 위해서는 `encodeURIComponent`를 확장하여 RFC 2396 → RFC 3986을 충족시킬 수 있게끔 만드는 것도 고려하자.

```typescript
function encodeRFC3986URIComponent(value: string) {
  return encodeURIComponent(value).replace(
    /[!'()*]/g,
    (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
  );
}
```

### 참고 자료

[퍼센트 인코딩](https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%84%BC%ED%8A%B8_%EC%9D%B8%EC%BD%94%EB%94%A9)

[URLSearchParams - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams#preserving_plus_signs)

[encodeURI() - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encoding_for_rfc3986)

[encodeURIComponent() - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#encoding_for_rfc3986)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://baek2back.gitbook.io/fundamental/misc/url-searchparams-encodeuri-component.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
