Skip to content

路由

¥Routing

Web 服务器使用请求的路径和 HTTP 方法来查找正确的资源,称为 "routing"。

¥Web servers use the request's path and HTTP method to look up the correct resource, referred to as "routing".

我们可以通过调用以 HTTP 动词命名的方法,传递路径和匹配时要执行的函数来定义路由。

¥We can define a route by calling a method named after HTTP verbs, passing a path and a function to execute when matched.

typescript
import { Elysia } from 'elysia'

new Elysia()
    .get('/', 'hello')
    .get('/hi', 'hi')
    .listen(3000)

我们可以通过访问 http://localhost:3000 来访问 Web 服务器。

¥We can access the web server by going to http://localhost:3000

默认情况下,Web 浏览器在访问页面时会默认发送 GET 方法。

¥By default, web browsers will send a GET method when visiting a page.

localhost

GET

提示

使用上面的交互式浏览器,将鼠标悬停在蓝色高亮区域上,即可查看不同路径之间的不同结果。

¥Using the interactive browser above, hover on the blue highlight area to see different results between each path.

路径类型

¥Path type

Elysia 中的路径可分为 3 种类型:

¥Path in Elysia can be grouped into 3 types:

  • 静态路径 - 用于定位资源的静态字符串

  • 动态路径 - segment 可以是任意值

  • wildcards - 直到特定点的路径可以是任意值

你可以将所有路径类型组合在一起,为你的 Web 服务器构建一个行为。

¥You can use all of the path types together to compose a behavior for your web server.

优先级如下:

¥The priorities are as follows:

  1. 静态路径
  2. 动态路径
  3. wildcards

如果路径解析为静态通配符动态路径,Elysia 将解析静态路径而不是动态路径。

¥If the path is resolved as the static wild dynamic path is presented, Elysia will resolve the static path rather than the dynamic path

typescript
import { Elysia } from 'elysia'

new Elysia()
    .get('/id/1', 'static path')
    .get('/id/:id', 'dynamic path')
    .get('/id/*', 'wildcard path')
    .listen(3000)
localhost

GET

服务器将响应如下:

¥Here the server will respond as follows:

路径响应
/id/1静态路径
/id/2动态路径
/id/2/a通配符路径

静态路径

¥Static Path

路径或路径名是用于定位服务器资源的标识符。

¥A path or pathname is an identifier to locate resources of a server.

bash
http://localhost:/path/page

Elysia 使用路径和方法来查找正确的资源。

¥Elysia uses the path and method to look up the correct resource.

URL Representation

路径从源位置开始。以 / 为前缀,并在搜索查询 (?) 前结束

¥A path starts after the origin. Prefix with / and ends before search query (?)

我们可以将 URL 和路径分类如下:

¥We can categorize the URL and path as follows:

URL路径
http://example.com//
http://example.com/hello/hello
http://example.com/hello/world/hello/world
http://example.com/hello?name=salt/hello
http://example.com/hello#title/hello

提示

如果未指定路径,浏览器和 Web 服务器将默认将路径视为 '/'。

¥If the path is not specified, the browser and web server will treat the path as '/' as a default value.

Elysia 将使用 handler 函数查找每个请求中的 route 和响应。

¥Elysia will look up each request for route and response using handler function.

动态路径

¥Dynamic path

URL 可以是静态的,也可以是动态的。

¥URLs can be both static and dynamic.

静态路径是硬编码的字符串,可用于在服务器上定位资源,而动态路径则匹配部分内容并捕获值以提取额外信息。

¥Static paths are hardcoded strings that can be used to locate resources on the server, while dynamic paths match some part and capture the value to extract extra information.

例如,我们可以从路径名中提取用户 ID。例如:

¥For instance, we can extract the user ID from the pathname. For example:

typescript
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
get
('/id/:id', ({
params
: {
id
} }) =>
id
)
.
listen
(3000)

这里,使用 /id/:id 创建了一个动态路径,它告诉 Elysia 匹配到 /id 的任何路径。之后的内容将存储在 params 对象中。

¥Here, a dynamic path is created with /id/:id which tells Elysia to match any path up until /id. What comes after that is then stored in the params object.

localhost

GET

1

请求时,服务器应返回如下响应:

¥When requested, the server should return the response as follows:

路径响应
/id/11
/id/123123
/id/anythinganything
/id/anything?name=saltanything
/id未找到
/id/anything/rest未找到

动态路径非常适合包含 ID 之类的内容,以便以后使用。

¥Dynamic paths are great to include things like IDs, which then can be used later.

我们将命名变量路径称为路径参数或简称 params。

¥We refer to the named variable path as path parameter or params for short.

¥Segment

URL 段是组成完整路径的每个路径。

¥URL segments are each path that is composed into a full path.

段由 / 分隔。

¥Segments are separated by /.

Representation of URL segments

Elysia 中的路径参数通过在片段前添加 ':' 前缀加上名称来表示。

¥Path parameters in Elysia are represented by prefixing a segment with ':' followed by a name.

Representation of path parameter

路径参数允许 Elysia 捕获 URL 的特定片段。

¥Path parameters allow Elysia to capture a specific segment of a URL.

命名路径参数将存储在 Context.params 中。

¥The named path parameter will then be stored in Context.params.

路由路径参数
/id/:id/id/1id=1
/id/:id/id/hiid=hi
/id/:name/id/hiname=hi

多个路径参数

¥Multiple path parameters

你可以拥有任意数量的路径参数,这些参数将被存储到 params 对象中。

¥You can have as many path parameters as you like, which will then be stored into a params object.

typescript
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
get
('/id/:id', ({
params
: {
id
} }) =>
id
)
.
get
('/id/:id/:name', ({
params
: {
id
,
name
} }) =>
id
+ ' ' +
name
)
.
listen
(3000)


localhost

GET

1

服务器将响应如下:

¥The server will respond as follows:

路径响应
/id/11
/id/123123
/id/anythinganything
/id/anything?name=saltanything
/id未找到
/id/anything/rest其他任何操作

可选路径参数

¥Optional path parameters

有时我们可能需要一个静态和动态路径来解析同一个处理程序。

¥Sometime we might want a static and dynamic path to resolve the same handler.

我们可以通过在参数名称后添加问号 ? 来使路径参数成为可选参数。

¥We can make a path parameter optional by adding a question mark ? after the parameter name.

typescript
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
get
('/id/:id?', ({
params
: {
id
} }) => `id ${
id
}`)
.
listen
(3000)

localhost

GET

服务器将响应如下:

¥The server will respond as follows:

路径响应
/idid 未定义
/id/1id 1

通配符

¥Wildcards

动态路径允许捕获 URL 的某些部分。

¥Dynamic paths allow capturing certain segments of the URL.

但是,当你需要路径值更具动态性并希望捕获 URL 段的其余部分时,可以使用通配符。

¥However, when you need a value of the path to be more dynamic and want to capture the rest of the URL segment, a wildcard can be used.

通配符可以通过使用 "*" 捕获段后的值,无论其大小。

¥Wildcards can capture the value after segment regardless of amount by using "*".

typescript
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
get
('/id/*', ({
params
}) =>
params
['*'])
.
listen
(3000)

localhost

GET

1

在这种情况下,服务器将响应如下:

¥In this case the server will respond as follows:

路径响应
/id/11
/id/123123
/id/anythinganything
/id/anything?name=saltanything
/id未找到
/id/anything/restanything/rest

通配符对于捕获到特定点的路径非常有用。

¥Wildcards are useful for capturing a path until a specific point.

提示

你可以将通配符与路径参数一起使用。

¥You can use a wildcard with a path parameter.

HTTP 动词

¥HTTP Verb

HTTP 定义了一组请求方法来指示针对给定资源需要执行的操作。

¥HTTP defines a set of request methods to indicate the desired action to be performed for a given resource

HTTP 动词有多种,但最常用的是:

¥There are several HTTP verbs, but the most common ones are:

GET

使用 GET 的请求应该只检索数据。

¥Requests using GET should only retrieve data.

POST

向指定资源提交有效负载,通常会导致状态更改或副作用。

¥Submits a payload to the specified resource, often causing state change or side effect.

PUT

使用请求的有效负载替换目标资源的所有当前表示。

¥Replaces all current representations of the target resource using the request's payload.

PATCH

对资源应用部分修改。

¥Applies partial modifications to a resource.

DELETE

删除指定的资源。

¥Deletes the specified resource.


为了处理每个不同的动词,Elysia 默认为多个 HTTP 动词内置了 API,类似于 Elysia.get

¥To handle each of the different verbs, Elysia has a built-in API for several HTTP verbs by default, similar to Elysia.get

typescript
import { Elysia } from 'elysia'

new Elysia()
    .get('/', 'hello')
    .post('/hi', 'hi')
    .listen(3000)
localhost

GET

Elysia HTTP 方法接受以下参数:

¥Elysia HTTP methods accepts the following parameters:

  • 路径:路径名

  • 功能:响应客户端的函数

  • 钩子:附加元数据

你可以在 HTTP 请求方法 上阅读有关 HTTP 方法的更多信息。

¥You can read more about the HTTP methods on HTTP Request Methods.

自定义方法

¥Custom Method

我们可以使用 Elysia.route 接受自定义 HTTP 方法。

¥We can accept custom HTTP Methods with Elysia.route.

typescript
import { Elysia } from 'elysia'

const app = new Elysia()
    .get('/get', 'hello')
    .post('/post', 'hi')
    .route('M-SEARCH', '/m-search', 'connect') 
    .listen(3000)
localhost

GET

Elysia.route 接受以下参数:

¥Elysia.route accepts the following:

  • 方法:HTTP 动词

  • 路径:路径名

  • 功能:响应客户端的函数

  • 钩子:附加元数据

导航到每个方法时,你应该看到以下结果:

¥When navigating to each method, you should see the results as the following:

路径方法结果
/getGEThello
/postPOSThi
/m-searchM-SEARCHconnect

提示

基于 RFC 7231,HTTP 动词区分大小写。

¥Based on RFC 7231, HTTP Verb is case-sensitive.

建议使用大写约定在 Elysia 中定义自定义 HTTP 动词。

¥It's recommended to use the UPPERCASE convention for defining a custom HTTP Verb with Elysia.

Elysia.all

Elysia 提供了一个 Elysia.all 接口,用于处理指定路径的任何 HTTP 方法,其 API 与 Elysia.get 和 Elysia.post 相同。

¥Elysia provides an Elysia.all for handling any HTTP method for a specified path using the same API like Elysia.get and Elysia.post

typescript
import { Elysia } from 'elysia'

new Elysia()
    .all('/', 'hi')
    .listen(3000)
localhost

GET

任何与路径匹配的 HTTP 方法都将按以下方式处理:

¥Any HTTP method that matches the path, will be handled as follows:

路径方法结果
/GEThi
/POSThi
/DELETEhi

句柄

¥Handle

大多数开发者使用 REST 客户端(例如 Postman、Insomnia 或 Hoppscotch)来测试他们的 API。

¥Most developers use REST clients like Postman, Insomnia or Hoppscotch to test their API.

然而,Elysia 可以使用 Elysia.handle 进行编程测试。

¥However, Elysia can be programmatically test using Elysia.handle.

typescript
import { Elysia } from 'elysia'

const app = new Elysia()
    .get('/', 'hello')
    .post('/hi', 'hi')
    .listen(3000)

app.handle(new Request('http://localhost/')).then(console.log)

Elysia.handle 是一个用于处理发送到服务器的实际请求的函数。

¥Elysia.handle is a function to process an actual request sent to the server.

提示

与单元测试的模拟不同,你可以期望它的行为类似于发送到服务器的实际请求。

¥Unlike unit test's mock, you can expect it to behave like an actual request sent to the server.

但它对于模拟或创建单元测试也很有用。

¥But also useful for simulating or creating unit tests.

404

如果没有路径与定义的路由匹配,Elysia 会将请求传递到 error 生命周期,然后返回 HTTP 状态为 404 的 "NOT_FOUND"。

¥If no path matches the defined routes, Elysia will pass the request to error life cycle before returning a "NOT_FOUND" with an HTTP status of 404.

我们可以通过从 error 生命周期返回一个值来处理自定义 404 错误,如下所示:

¥We can handle a custom 404 error by returning a value from error life cycle like this:

typescript
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
get
('/', 'hi')
.
onError
(({
code
}) => {
if (
code
=== 'NOT_FOUND') {
return 'Route not found :(' } }) .
listen
(3000)
localhost

GET

导航到你的 Web 服务器时,你应该看到以下结果:

¥When navigating to your web server, you should see the result as follows:

路径方法结果
/GEThi
/POST未找到路由 😦
/hiGET未找到路由 😦

你可以在 生命周期事件错误处理 中了解有关生命周期和错误处理的更多信息。

¥You can learn more about life cycle and error handling in Life Cycle Events and Error Handling.

提示

HTTP 状态用于指示响应类型。默认情况下,如果一切正常,服务器将返回 '200 OK' 状态码(如果路由匹配且没有错误,Elysia 默认返回 200)。

¥HTTP Status is used to indicate the type of response. By default if everything is correct, the server will return a '200 OK' status code (If a route matches and there is no error, Elysia will return 200 as default)

如果服务器找不到任何要处理的路由(例如本例),则服务器将返回 '404 NOT FOUND' 状态码。

¥If the server fails to find any route to handle, like in this case, then the server shall return a '404 NOT FOUND' status code.

¥Group

创建 Web 服务器时,通常会有多个路由共享相同的前缀:

¥When creating a web server, you would often have multiple routes sharing the same prefix:

typescript
import { Elysia } from 'elysia'

new Elysia()
    .post('/user/sign-in', 'Sign in')
    .post('/user/sign-up', 'Sign up')
    .post('/user/profile', 'Profile')
    .listen(3000)
localhost

POST

这可以通过 Elysia.group 进行改进,允许我们通过将前缀分组同时应用于多个路由:

¥This can be improved with Elysia.group, allowing us to apply prefixes to multiple routes at the same time by grouping them together:

typescript
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
group
('/user', (
app
) =>
app
.
post
('/sign-in', 'Sign in')
.
post
('/sign-up', 'Sign up')
.
post
('/profile', 'Profile')
) .
listen
(3000)
localhost

POST

此代码的行为与我们的第一个示例相同,其结构应如下:

¥This code behaves the same as our first example and should be structured as follows:

路径结果
/user/sign-in登录
/user/sign-up注册
/user/profile配置文件

.group() 还可以接受可选的守卫参数,以减少同时使用组和守卫的重复工作:

¥.group() can also accept an optional guard parameter to reduce boilerplate of using groups and guards together:

typescript
import { 
Elysia
,
t
} from 'elysia'
new
Elysia
()
.
group
(
'/user', {
body
:
t
.
Literal
('Rikuhachima Aru')
}, (
app
) =>
app
.
post
('/sign-in', 'Sign in')
.
post
('/sign-up', 'Sign up')
.
post
('/profile', 'Profile')
) .
listen
(3000)

你可以在 scope 中找到更多关于分组守卫的信息。

¥You may find more information about grouped guards in scope.

前缀

¥Prefix

我们可以将一个组分离到一个单独的插件实例中,通过在构造函数中添加前缀来减少嵌套。

¥We can separate a group into a separate plugin instance to reduce nesting by providing a prefix to the constructor.

typescript
import { Elysia } from 'elysia'

const users = new Elysia({ prefix: '/user' })
    .post('/sign-in', 'Sign in')
    .post('/sign-up', 'Sign up')
    .post('/profile', 'Profile')

new Elysia()
    .use(users)
    .get('/', 'hello world')
    .listen(3000)
localhost

GET