伺服器
server/
目錄用於註冊應用程式的 API 和伺服器處理器。Nuxt 會自動掃描這些目錄中的檔案,以註冊 API 和伺服器處理器,並支援熱模組替換 (HMR)。
-| server/
---| api/
-----| hello.ts # /api/hello
---| routes/
-----| bonjour.ts # /bonjour
---| middleware/
-----| log.ts # log all requests
每個檔案都應匯出一個使用 defineEventHandler()
或 eventHandler()
(別名)定義的預設函式。
處理器可以直接返回 JSON 資料、Promise
,或使用 event.node.res.end()
來傳送回應。
export default defineEventHandler((event) => {
return {
hello: 'world'
}
})
現在您可以在頁面和元件中通用地呼叫此 API
<script setup lang="ts">
const { data } = await useFetch('/api/hello')
</script>
<template>
<pre>{{ data }}</pre>
</template>
伺服器路由
~/server/api
內的檔案會在其路由中自動加上 /api
前綴。
若要新增沒有 /api
前綴的伺服器路由,請將它們放入 ~/server/routes
目錄中。
範例
export default defineEventHandler(() => 'Hello World!')
以上述範例為例,/hello
路由將可透過 https://127.0.0.1:3000/hello 存取。
伺服器中介軟體
Nuxt 會自動讀取 ~/server/middleware
中的任何檔案,以為您的專案建立伺服器中介軟體。
中介軟體處理器將在任何其他伺服器路由之前,在每個請求上執行,以新增或檢查標頭、記錄請求或擴展事件的請求物件。
範例
export default defineEventHandler((event) => {
console.log('New request: ' + getRequestURL(event))
})
export default defineEventHandler((event) => {
event.context.auth = { user: 123 }
})
伺服器外掛
Nuxt 會自動讀取 ~/server/plugins
目錄中的任何檔案,並將其註冊為 Nitro 外掛。這允許擴展 Nitro 的執行階段行為,並掛接到生命週期事件。
範例
export default defineNitroPlugin((nitroApp) => {
console.log('Nitro plugin', nitroApp)
})
伺服器公用程式
伺服器路由由 unjs/h3 提供支援,其中包含一組方便的輔助程式。
您可以在 ~/server/utils
目錄中自行新增更多輔助程式。
例如,您可以定義一個自訂處理器公用程式,該公用程式會封裝原始處理器,並在返回最終回應之前執行其他作業。
範例
import type { EventHandler, EventHandlerRequest } from 'h3'
export const defineWrappedResponseHandler = <T extends EventHandlerRequest, D> (
handler: EventHandler<T, D>
): EventHandler<T, D> =>
defineEventHandler<T>(async event => {
try {
// do something before the route handler
const response = await handler(event)
// do something after the route handler
return { response }
} catch (err) {
// Error handling
return { err }
}
})
伺服器類型
為了改善 IDE 中 'nitro' 和 'vue' 的自動匯入之間的清晰度,您可以新增具有以下內容的 ~/server/tsconfig.json
{
"extends": "../.nuxt/tsconfig.server.json"
}
目前,這些值在類型檢查時不會被採用(nuxi typecheck
),但您應該在 IDE 中獲得更好的類型提示。
食譜
路由參數
伺服器路由可以在檔案名稱中,使用方括號內的動態參數,例如 /api/hello/[name].ts
,並可透過 event.context.params
存取。
export default defineEventHandler((event) => {
const name = getRouterParam(event, 'name')
return `Hello, ${name}!`
})
現在,您可以在 /api/hello/nuxt
上通用地呼叫此 API,並取得 Hello, nuxt!
。
比對 HTTP 方法
處理檔案名稱可以加上 .get
、.post
、.put
、.delete
... 等後綴,以比對請求的 HTTP 方法。
export default defineEventHandler(() => 'Test get handler')
export default defineEventHandler(() => 'Test post handler')
以上述範例為例,使用以下方式請求 /test
:
- GET 方法:回傳
Test get handler
- POST 方法:回傳
Test post handler
- 任何其他方法:回傳 405 錯誤
您也可以在目錄內使用 index.[method].ts
來以不同的方式組織程式碼,這對於建立 API 命名空間很有用。
export default defineEventHandler((event) => {
// handle GET requests for the `api/foo` endpoint
})
萬用路由 (Catch-all Route)
萬用路由對於處理後備路由很有幫助。
例如,建立一個名為 ~/server/api/foo/[...].ts
的檔案,將會為所有不符合任何路由處理程式的請求註冊一個萬用路由,例如 /api/foo/bar/baz
。
export default defineEventHandler((event) => {
// event.context.path to get the route path: '/api/foo/bar/baz'
// event.context.params._ to get the route segment: 'bar/baz'
return `Default foo handler`
})
您可以使用 ~/server/api/foo/[...slug].ts
為萬用路由設定一個名稱,並透過 event.context.params.slug
來存取它。
export default defineEventHandler((event) => {
// event.context.params.slug to get the route segment: 'bar/baz'
return `Default foo handler`
})
Body 處理
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return { body }
})
您現在可以使用以下方式通用地呼叫此 API:
<script setup lang="ts">
async function submit() {
const { body } = await $fetch('/api/submit', {
method: 'post',
body: { test: 123 }
})
}
</script>
submit.post.ts
只是為了匹配接受請求主體的 POST
方法。在 GET 請求中使用 readBody
時,readBody
將會拋出 405 Method Not Allowed
HTTP 錯誤。查詢參數
範例查詢:/api/query?foo=bar&baz=qux
export default defineEventHandler((event) => {
const query = getQuery(event)
return { a: query.foo, b: query.baz }
})
錯誤處理
如果沒有拋出任何錯誤,將會回傳 200 OK
的狀態碼。
任何未捕獲的錯誤將會回傳 500 Internal Server Error
HTTP 錯誤。
若要回傳其他錯誤碼,請使用 createError
拋出例外。
export default defineEventHandler((event) => {
const id = parseInt(event.context.params.id) as number
if (!Number.isInteger(id)) {
throw createError({
statusCode: 400,
statusMessage: 'ID should be an integer',
})
}
return 'All good'
})
狀態碼
若要回傳其他狀態碼,請使用 setResponseStatus
工具。
例如,要回傳 202 Accepted
:
export default defineEventHandler((event) => {
setResponseStatus(event, 202)
})
執行階段設定
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig(event)
const repo = await $fetch('https://api.github.com/repos/nuxt/nuxt', {
headers: {
Authorization: `token ${config.githubToken}`
}
})
return repo
})
請求 Cookies
export default defineEventHandler((event) => {
const cookies = parseCookies(event)
return { cookies }
})
轉發 Context & Headers
預設情況下,當在伺服器路由中發出 fetch 請求時,不會轉發來自傳入請求的標頭或請求 context。您可以使用 event.$fetch
在伺服器路由中發出 fetch 請求時轉發請求 context 和標頭。
export default defineEventHandler((event) => {
return event.$fetch('/api/forwarded')
})
transfer-encoding
、connection
、keep-alive
、upgrade
、expect
、host
、accept
回應後等待 Promise
在處理伺服器請求時,您可能需要執行不應阻止客戶端回應的非同步任務(例如,快取和記錄)。您可以使用 event.waitUntil
在背景中等待 Promise,而不會延遲回應。
event.waitUntil
方法接受一個 Promise,該 Promise 將在處理程式終止之前等待,確保即使伺服器在傳送回應後立即終止處理程式,任務也會完成。這與執行階段供應商整合,以利用其原生功能來處理回應傳送後的非同步操作。
const timeConsumingBackgroundTask = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
};
export default eventHandler((event) => {
// schedule a background task without blocking the response
event.waitUntil(timeConsumingBackgroundTask())
// immediately send the response to the client
return 'done'
});
進階用法
Nitro 設定
您可以使用 nuxt.config
中的 nitro
鍵直接設定 Nitro 設定。
export default defineNuxtConfig({
// https://nitro.unjs.io/config
nitro: {}
})
巢狀路由
import { createRouter, defineEventHandler, useBase } from 'h3'
const router = createRouter()
router.get('/test', defineEventHandler(() => 'Hello World'))
export default useBase('/api/hello', router.handler)
傳送串流
import fs from 'node:fs'
import { sendStream } from 'h3'
export default defineEventHandler((event) => {
return sendStream(event, fs.createReadStream('/path/to/file'))
})
傳送重新導向
export default defineEventHandler(async (event) => {
await sendRedirect(event, '/path/redirect/to', 302)
})
舊版處理程式或中介軟體
export default fromNodeMiddleware((req, res) => {
res.end('Legacy handler')
})
export default fromNodeMiddleware((req, res, next) => {
console.log('Legacy middleware')
next()
})
next()
回呼與 async
或回傳 Promise
的舊版中介軟體結合使用。伺服器儲存
Nitro 提供跨平台的 儲存層。為了設定額外的儲存掛載點,您可以使用 nitro.storage
或 伺服器外掛程式。
新增 Redis 儲存的範例
使用 nitro.storage
export default defineNuxtConfig({
nitro: {
storage: {
redis: {
driver: 'redis',
/* redis connector options */
port: 6379, // Redis port
host: "127.0.0.1", // Redis host
username: "", // needs Redis >= 6
password: "",
db: 0, // Defaults to 0
tls: {} // tls/ssl
}
}
}
})
然後在您的 API 處理程式中:
export default defineEventHandler(async (event) => {
// List all keys with
const keys = await useStorage('redis').getKeys()
// Set a key with
await useStorage('redis').setItem('foo', 'bar')
// Remove a key with
await useStorage('redis').removeItem('foo')
return {}
})
或者,您可以使用伺服器外掛程式和執行階段設定來建立儲存掛載點
import redisDriver from 'unstorage/drivers/redis'
export default defineNitroPlugin(() => {
const storage = useStorage()
// Dynamically pass in credentials from runtime configuration, or other sources
const driver = redisDriver({
base: 'redis',
host: useRuntimeConfig().redis.host,
port: useRuntimeConfig().redis.port,
/* other redis connector options */
})
// Mount driver
storage.mount('redis', driver)
})