Skip to content
Our Sponsors
Open in Anthropic

title: 扩展上下文 - Elysia 教程 layout: false search: false authors: [] head: - - meta - property: 'og:title' content: 扩展上下文 - ElysiaJS

- - meta
  - name: 'description'
    content: 学习如何使用 Decorate、State、Resolve 和 Derive 在 Elysia 中扩展上下文,以增强您的 Web 应用程序。

- - meta
  - property: 'og:description'
    content: 学习如何使用 Decorate、State、Resolve 和 Derive 在 Elysia 中扩展上下文,以增强您的 Web 应用程序。

扩展上下文

Elysia 提供了一个带有小型实用工具的上下文,帮助您入门。

您可以通过以下方式扩展 Elysia 的上下文:

  1. Decorate
  2. State
  3. Resolve
  4. Derive

Decorate

单例,且不可变,在所有请求之间共享。

typescript
import { Elysia } from 'elysia'

class Logger {
    log(value: string) {
        console.log(value)
    }
}

new Elysia()
    .decorate('logger', new Logger())
    .get('/', ({ logger }) => {
        logger.log('hi')

        return 'hi'
    })

装饰值将作为只读属性在上下文中可用,请参阅 Decorate

State

一个在所有请求之间共享的可变引用。

typescript
import { Elysia } from 'elysia'

new Elysia()
	.state('count', 0)
	.get('/', ({ store }) => {
		store.count++

		return store.count
	})

状态将在 context.store 中可用,它在每个请求之间共享,请参阅 State

Resolve / Derive

Decorate 值被注册为单例。

ResolveDerive 允许您按请求抽象上下文值。

typescript
import { Elysia } from 'elysia'

new Elysia()
	.derive(({ headers: { authorization } }) => ({
		authorization
	}))
	.get('/', ({ authorization }) => authorization)

任何返回值都将在上下文中可用,但 status 除外,它将直接发送给客户端,并中止后续的处理程序。

resolvederive 的语法类似,但它们有不同的用例。

在底层,两者都是生命周期的语法糖(带有类型安全)

由于 derive 基于 transform,意味着数据尚未经过验证和强制转换/转换。如果您需要经过验证的数据,最好使用 resolve

作用域

StateDecorate 在所有请求和实例之间共享。
ResolveDerive 是按请求的,并且具有封装作用域(因为它们基于生命周期事件)

如果您想使用来自插件的解析/派生值,则必须声明一个 Scope

typescript
import { Elysia } from 'elysia'

const plugin = new Elysia()
	.derive(
		{ as: 'scoped' }, 
		({ headers: { authorization } }) => ({
			authorization
		})
	)

new Elysia()
	.use(plugin)
	.get('/', ({ authorization }) => authorization)
	.listen(3000)

练习

让我们尝试扩展 Elysia 的上下文。

  1. Extract "query.age"

    Let's extract a "query.age" as "age". If it doesn't existed, return 401.

  2. Use "age"

    In a main handler of GET "/profile", return a value of "age" from the context

Show answer

我们可以使用 resolve 从查询中提取 age。

typescript
import { Elysia, t } from 'elysia'

class Logger {
	log(info: string) {
		console.log(info)
	}
}

new Elysia()
	.decorate('logger', new Logger())
	.onRequest(({ request, logger }) => {
		logger.log(`Request to ${request.url}`)
	})
	.guard({
		query: t.Optional(
			t.Object({
				age: t.Number({ min: 15 })
			})
		)
	})
	.resolve(({ query: { age }, status }) => {
		if(!age) return status(401)

		return { age }
	})
	.get('/profile', ({ age }) => age)
	.listen(3000)
  • index.ts