Nuxt.js 3【详解】服务器 Server

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

服务器架构

Nuxt.js 的服务端由 Nitro 实现,Nitro 由基于 H3 实现。

接口路由

  • 基于文件目录自动生成
  • 方法名取自文件后缀名

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

  1. 本地安装 redis,见教程

  2. 添加配置 nuxt.config.ts

    ts 复制代码
      nitro: {
        storage: {
          redis: {
            driver: "redis",
            port: 6379,
            host: "127.0.0.1",
            password: "",
            db: 0, // Defaults to 0
          },
        },
      },
  3. 存数据

    useStorage 的参数 redis 与 nuxt.config.ts 中的配置 storage 属性 redis 对应

    ts 复制代码
      await useStorage("redis").setItem(
        "currentUser",
        currentUser,
        // ttl 配置 redis的过期时间,单位s,此处为 10s 后过期
        { ttl: 10 }
      );
  4. 取数据

    ts 复制代码
        const 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"
    }
  ]
}
相关推荐
程序员JerrySUN18 分钟前
从底层驱动到 OpenCV:深入解析 Linux 摄像头完整技术栈
linux·服务器·开发语言·人工智能·opencv·计算机视觉
Bunury21 分钟前
flex布局自定义一行几栏,靠左对齐===grid布局
前端·javascript·html
雷神乐乐28 分钟前
分布式主键生成服务
java·服务器·微服务·主键生成·数据库乐观锁
大道归简32 分钟前
Web网页开发——水果忍者
前端·javascript·html
傻小胖1 小时前
React 高阶组件(HOC)
前端·javascript·react.js
yqcoder2 小时前
Express + MongoDB 实现更新用户时用户名变化验证数据库是否存在,不变不验证
服务器·数据库·oracle
问道飞鱼2 小时前
【Linux知识】Linux上从源码编译到软件安装全过程详细说明
linux·运维·服务器·编译
bossface3 小时前
ES的简单讲解
服务器·c++·json·gtest·etcd·spdlog
学途路漫漫3 小时前
怎么修改node_modules里的文件,怎么使用patch-package修改node_modules的文件,怎么修改第三方库原文件。
开发语言·javascript·ecmascript
我命由我123453 小时前
34.Java 阻塞队列(阻塞队列架构、阻塞队列分类、阻塞队列核心方法)
java·服务器·开发语言·后端·架构·java-ee·后端开发