경로 처리
m.route
및 m.request
는 각각 경로(path)라는 개념을 사용합니다. 이는 라우팅하거나 데이터를 가져올 URL을 생성하는 데 활용됩니다.
경로 유형
일반적으로 생(raw) 경로와 파라미터화된 경로, 두 가지 유형이 있습니다.
- 생(raw) 경로는 URL로 직접 사용되는 단순한 문자열입니다. 값의 대체나 분할 없이, 모든 매개변수가 URL 끝에 추가되어 정규화됩니다.
- 파라미터화된 경로는 URL 주입 공격으로부터 안전하도록 기본적으로 이스케이프된 값을 경로에 삽입할 수 있습니다.
m.request
의 경우 거의 모든 URL을 사용할 수 있지만, m.route
의 경우 스킴이나 도메인 없는 절대 URL 경로명만 가능합니다.
경로 매개변수
경로 매개변수는 다음과 같이 두 가지 형식을 가집니다.
:foo
-params.foo
값을 URL에 삽입하며, 먼저 해당 값을 이스케이프 처리합니다.:foo...
-params.foo
값을 이스케이프 처리 없이 원시 형태로 URL에 삽입합니다.
여기서 params
객체는 m.route.set(path, params)
또는 m.request({url, params})
에 전달되는 params
를 의미합니다.
m.route(root, defaultRoute, routes)
를 통해 경로를 수신할 때, 이러한 매개변수를 사용하여 경로에서 값을 추출할 수 있습니다. 이는 경로를 생성하는 방식과 유사하지만, 방향이 반대입니다.
// 단일 항목 수정
m.route(document.body, '/edit/1', {
'/edit/:id': {
view: function () {
return [m(Menu), m('h1', '사용자 수정 ' + m.route.param('id'))];
},
},
});
// 경로로 식별되는 항목 수정
m.route(document.body, '/edit/pictures/image.jpg', {
'/edit/:file...': {
view: function () {
return [m(Menu), m('h1', '파일 수정 ' + m.route.param('file'))];
},
},
});
위 예제에서 기본 경로로 이동한다고 가정할 때, m.route.param("id")
는 "1"
로 읽히고 m.route.param("file")
은 pictures/image.jpg
로 읽힙니다.
경로 매개변수는 /
, -
, 또는 .
로 구분될 수 있습니다. 이를 통해 동적인 경로 구간을 구성하여 단순한 경로명보다 훨씬 유연하게 사용할 수 있습니다. 예를 들어 파일 확장자를 기반으로 수정하기 위해 "/edit/:name.:ext"
와 같은 경로를 사용하거나, 지역화된 경로를 위해 /:lang-:region/view"
와 같은 경로를 사용할 수 있습니다.
경로 매개변수는 탐욕적인 방식으로 작동합니다. 선언된 경로 "/edit/:name.:ext"
가 주어졌을 때, /edit/file.test.png
로 이동하면 추출된 매개변수는 {name: "file.test", ext: "png"}
가 되며, {name: "file", ext: "test.png"}
가 되지 않습니다. 마찬가지로 "/route/:path.../view/:child..."
가 주어지면 /route/foo/view/bar/view/baz
로 이동했을 때 추출된 매개변수는 {path: "foo/view/bar", child: "baz"}
가 됩니다.
매개변수 정규화
경로 이름에 삽입된 경로 매개변수는 편의성을 높이고 경로 이름을 간결하게 유지하기 위해 쿼리 스트링에서 생략됩니다. 예를 들어, URL 스트링에서 중복된 id=1
을 생략하고 GET /api/user/1/connections?sort=name-asc
와 같은 서버 요청을 보냅니다.
m.request({
url: 'https://example.com/api/user/:userID/connections',
params: {
userID: 1,
sort: 'name-asc',
},
});
다음과 같이 쿼리 스트링 자체에서 명시적으로 매개변수를 지정할 수도 있습니다. 이는 위와 동일한 결과를 냅니다.
m.request({
url: 'https://example.com/api/user/:userID/connections?sort=name-asc',
params: {
userID: 1,
},
});
물론 혼합하여 사용할 수도 있습니다. 이는 GET /api/user/1/connections?sort=name-asc&first=10
에 대한 요청을 실행합니다.
m.request({
url: 'https://example.com/api/user/:userID/connections?sort=name-asc',
params: {
userID: 1,
first: 10,
},
});
이러한 특징은 경로 일치에도 적용됩니다. 명시적인 쿼리 스트링이 있는 경로와 일치시킬 수 있으며, 편의를 위해 일치된 매개변수를 유지하므로 vnode 파라미터 또는 m.route.param
을 통해 액세스할 수 있습니다. 이러한 방식이 가능하기는 하지만, 일반적으로는 권장되지 않습니다. 페이지 탐색에는 경로를 사용하는 것이 더 적합하기 때문입니다. 특정 파일 형식에 따라 약간 다른 뷰를 보여줘야 할 때 유용할 수 있지만, 논리적으로는 별도의 페이지가 아닌 쿼리 매개변수와 유사합니다.
// 참고: 일반적으로 *권장되지 않습니다*. 쿼리 스트링이 아닌 경로 선언에 경로를 사용하는 것이 좋습니다.
m.route(document.body, '/edit/1', {
'/edit?type=image': {
view: function () {
return [m(Menu), m('h1', '사진 수정')];
},
},
'/edit': {
view: function () {
return [m(Menu), m('h1', '수정 ' + m.route.param('type'))];
},
},
});
쿼리 매개변수는 암묵적으로 사용됩니다. 이를 수락하기 위해 이름을 지정할 필요가 없습니다. "/edit?type=image"
와 같이 기존 값을 기반으로 일치시킬 수 있지만, 값을 수락하기 위해 "/edit?type=:type"
을 사용할 필요는 없습니다. 실제로 Mithril.js는 이를 m.route.param("type") === ":type"
에 대해 문자 그대로 일치시키려고 시도하는 것으로 취급하므로 권장하지 않습니다. 쿼리 매개변수를 읽으려면 m.route.param("key")
또는 경로 컴포넌트 어트리뷰트를 사용하십시오.
경로 정규화
파싱된 경로는 항상 모든 중복 매개변수와 추가 슬래시가 제거된 상태로 반환되며, 항상 슬래시로 시작합니다. 이러한 사소한 차이점들이 라우팅 및 경로 처리를 불필요하게 복잡하게 만들 수 있습니다. Mithril.js는 라우팅을 위해 내부적으로 경로를 정규화하지만, 현재 정규화된 경로를 직접 노출하지는 않습니다. (m.parsePathname(m.route.get()).path
를 통해 계산할 수 있습니다.)
일치하는 동안 매개변수가 중복 제거되는 과정에서 쿼리 스트링의 매개변수가 경로명의 매개변수보다 우선하고, URL 끝에 있는 매개변수가 URL 시작 부분에 더 가까운 매개변수보다 우선합니다.
경로 이스케이프
일부 문자는 리터럴하게 사용하려면 이스케이프해야 합니다. encodeURIComponent
함수는 이러한 문자(및 더 많은 문자)를 인코딩하며, 매개변수를 대체하거나 쿼리 매개변수를 추가할 때 필요에 따라 자동으로 인코딩됩니다. 다음은 Mithril.js가 해석하는 문자입니다.
:
=%3A
/
=%2F
(경로에만 필요)%
=%25
?
=%3F
(경로에만 필요)#
=%23
물론 URL 사양에 따라 공백과 같이 이스케이프해야 하는 다른 문자도 있습니다. 그러나 encodeURIComponent
는 이를 수행하고 Mithril.js는 매개변수를 대체할 때 암시적으로 이를 사용합니다. 따라서 m.request("https://example.com/api/user/User%20Name/:field", {params: {field: ...}})
와 같이 URL에 직접 인코딩된 문자를 사용하는 경우에만 주의하면 됩니다.