Nuxt.js 是一个全栈框架,可以在一个项目中,同时完成前端和后端的开发。
服务器架构

Nuxt.js 的服务端由 Nitro 实现,Nitro 由基于 H3 实现。
- Nitro 官网 https://nitro.build/guide
- H3 官网 https://h3.unjs.io/guide
接口路由
- 基于文件目录自动生成
- 方法名取自文件后缀名
server/api
根据文件目录自动生成带 /api
前缀的接口
ts
api/
test.ts ---> /api/test
user/
// 动态接口,可得到接口参数 Param ,如 id 为 1
[id].ts ---> /api/user/1
ts
// server/api/test.ts
export default defineEventHandler(() => {
return { hello: "你好" };
});
启动项目后,浏览器访问 http://localhost:3030/api/test

server/routes
根据文件目录自动生成无 /api
前缀的接口
ts
routes/
hello.ts ---> GET /hello
hello.get.ts ---> GET /hello
hello.post.ts ---> POST /hello
参数解析
从网络请求的事件中,可以解析出必要的参数,内置的 API 如下:
ts
export default defineEventHandler(event => {
// 获取接口中的参数,如 /api/user/1 中的 1
const id = getRouterParam(event, 'id')
// 获取接口的 URL ,如 http://localhost:3030/api/user/1
const url = getRequestURL(event)
const age = getRouterParam(event, 'age')
return `Hello ${name}! You are ${age} years old.`
})
getRouterParam
获取 get 请求中的接口参数
ts
// 获取接口中的参数,如 /api/user/1 中的 1
const id = getRouterParam(event, 'id')
- 参数1:网络请求事件 event
- 参数2:请求参数的key
- 返回值:参数的值
getQuery
获取 get 请求中的查询参数
ts
const query = getQuery(event);
- 参数:网络请求事件 event
- 返回值:查询参数对象
如 http://localhost:3030/api/user/1?name=joy
会得到
ts
{
"name": "joy"
}
readBody
获取 post 请求中的 body 信息
ts
// routes/users.post.ts
export default defineEventHandler(async event => {
const body = await readBody(event)
})
getRequestURL
ts
const urlObj = getRequestURL(event)
-
参数为网络请求事件 event
-
返回一个URL对象,通过其属性,可以获取到其他 URL 信息
以 'http://localhost:3030/api/user/1?name=joy' 为例json{ href: 'http://localhost:3030/api/user/1?name=joy', origin: 'http://localhost:3030', protocol: 'http:', username: '', password: '', host: 'localhost:3030', hostname: 'localhost', port: '3030', pathname: '/api/user/1', search: '?name=joy', searchParams: URLSearchParams { 'name' => 'joy' }, hash: '' }
接口的配置
nitro.config.ts 中
ts
export default defineNitroConfig({
routeRules: {
"/blog/**": { swr: true },
"/blog/api1": { swr: 600 },
"/blog/api2": { static: true },
"/blog/api3": {
cache: {
/* cache options*/
},
},
"/assets/**": { headers: { "cache-control": "s-maxage=0" } },
"/api/v1/**": {
cors: true,
headers: { "access-control-allow-methods": "GET" },
},
"/old-page": { redirect: "/new-page" },
"/old-page/**": { redirect: "/new-page/**" },
"/proxy/example": { proxy: "https://example.com" },
"/proxy/**": { proxy: "/api/**" },
},
});
内置存储 useStorage
通过 useStorage() 可获取到一个内置存储的实例,可在内存中存储和读取数据。(通过 unstorage 实现,官网为 https://unstorage.unjs.io/guide)
ts
const currentUser = { name: body.name };
// 存数据 useStorage().setItem
await useStorage().setItem("user", currentUser);
ts
// 取数据 useStorage().getItem
const user = await useStorage().getItem("user");
if (!user) {
throw createError({
statusCode: 401,
statusMessage: "未登录",
});
}
改用 redis
-
本地安装 redis,见教程
-
添加配置 nuxt.config.ts
tsnitro: { storage: { redis: { driver: "redis", port: 6379, host: "127.0.0.1", password: "", db: 0, // Defaults to 0 }, }, },
-
存数据
useStorage 的参数
redis
与 nuxt.config.ts 中的配置 storage 属性 redis 对应tsawait useStorage("redis").setItem( "currentUser", currentUser, // ttl 配置 redis的过期时间,单位s,此处为 10s 后过期 { ttl: 10 } );
-
取数据
tsconst isLogin = await useStorage("redis").hasItem("currentUser"); if (!isLogin) { throw createError({ statusCode: 401, statusMessage: "未登录", }); }
中间件 server/middleware
server/middleware 目录中的文件为服务器的中间件,在请求接口前,都会依次执行!
默认执行顺序为按文件名排序。
可通过添加数字前缀,自定义执行顺序。

若想只在目标路由执行中间件,则需添加判断
ts
export default defineEventHandler((event) => {
// 仅在请求 /auth 接口时执行
if (getRequestURL(event).pathname.startsWith('/auth')) {
event.context.user = { name: 'Nitro' }
}
})
工具函数 server/utils
server/utils 目录中的工具函数,会自动导入
- 若用默认导出 export default ,则自动导入的函数名为文件名
- 若用具名导出 export function useSum ,则自动导入的函数名为函数定义的名称。
如
server/utils/sum.ts
ts
export function useSum(a: number, b: number) {
return a + b;
}
在接口文件中直接使用即可
ts
// routes/index.ts
export default defineEventHandler(() => {
const sum = useSum(1, 2) // auto-imported
return { sum }
})
若 server/utils/sum.ts 为
ts
export default function useSum(a: number, b: number) {
return a + b;
}
在接口文件中直接使用即可
ts
// routes/index.ts
export default defineEventHandler(() => {
const sumResult = sum(1, 2) // auto-imported
return { sumResult }
})
封装统一接口方法
server/utils/authHandler.ts
ts
import type { EventHandler } from "h3";
export const defineAuthResponseEventHandler = (handler: EventHandler) => {
return defineEventHandler(async (event) => {
const user = await useStorage().getItem("user");
if (!user) {
throw createError({
statusCode: 401,
statusMessage: "未登录",
});
}
const response = await handler(event);
return response;
});
};
插件 server/plugins
插件会在服务启动时执行,可以访问生命周期
范例:将 useStorage 改用 redis 存储
server/plugins/storage.ts
ts
import redisDriver from "unstorage/drivers/redis";
export default defineNitroPlugin((app) => {
const storage = useStorage();
const { redis } = useRuntimeConfig();
const driver = redisDriver({
host: redis.host,
port: redis.port,
});
storage.mount("redis", driver);
});
.env
ts
NUXT_REDIS_HOST=127.0.0.1
NUXT_REDIS_PORT=6379
nuxt.config.ts
ts
runtimeConfig: {
redis: {
host: "",
port: 0,
},
},
连接数据库
安装依赖
dos
npx nuxi@latest module add nuxt-mongoose
成功后,可见 nuxt.config.ts 的 modules 中添加了 "nuxt-mongoose"
在 .env 中添加配置( 本地 mongoDB 数据库的名称为 test )
js
MONGODB_URI=mongodb://localhost:27017/test
操作数据
创建 models
会自动注册
server/models/user.ts
ts
import { defineMongooseModel } from "#nuxt/mongoose";
interface UserProps {
name: string;
age: number;
}
export const UserSchema = defineMongooseModel<UserProps>(
"User",
{
name: { type: String, unique: true, required: true },
age: { type: Number, min: 0, max: 160 },
},
{
timestamps: true,
toJSON: {
// 过滤掉敏感字段
transform(doc, ret) {
delete ret.__v;
delete ret.password;
},
},
}
);
查询数据
server/api/user/index.ts
ts
export default defineEventHandler(async (event) => {
const userList = await UserSchema.find({})
.select(["name", "age"])
.limit(10)
.lean();
return { data: userList };
});
访问接口 http://localhost:3030/api/user 得到
ts
{
"data": [
{
"_id": "653bc7cc0b10e8b08834b3ff",
"name": "dos"
}
]
}