Nuxt.js 中的服务器中间件 (Server Middleware) 如何在 SSR 过程中处理 API 请求或认证逻辑?

各位老铁,晚上好!我是你们的老朋友,代码界的段子手,今天咱们聊聊 Nuxt.js 里的服务器中间件,看看它在 SSR 过程中是怎么耍的。

开场白:SSR 的那些事儿

话说,SSR (Server-Side Rendering,服务端渲染) 这玩意儿,一开始是为了 SEO 优化的,后来发现体验也更好,能更快地看到首屏。但它也有个问题,就是服务器压力大了。Nuxt.js 帮我们简化了 SSR 的流程,但有些逻辑,比如 API 请求、权限认证,还是得我们自己来。这时候,服务器中间件就派上用场了。

什么是 Nuxt.js 服务器中间件?

简单来说,服务器中间件就是一堆函数,它们会在每次请求到达服务器时被执行,可以修改请求、响应,或者直接终止请求。在 Nuxt.js 里,这些中间件运行在 Node.js 环境下,所以你可以访问 Node.js 的所有 API,比如文件系统、数据库等等。

服务器中间件的注册方式

Nuxt.js 提供了几种注册服务器中间件的方式:

  1. nuxt.config.js 中的 serverMiddleware 选项: 这是最常见的方式,直接在 nuxt.config.js 文件里配置。

    // nuxt.config.js
    export default {
      serverMiddleware: [
        // 字符串形式,指向一个文件
        '~/server-middleware/logger',
        // 对象形式,可以配置路径和处理函数
        { path: '/api', handler: '~/server-middleware/api' },
        // 直接使用函数 (inline middleware)
        (req, res, next) => {
          console.log('This is an inline middleware!');
          next();
        }
      ]
    }
  2. modules 选项 (配合模块使用): 有些 Nuxt.js 模块会自带服务器中间件,比如 @nuxtjs/axios,它会帮你代理 API 请求。

  3. server 目录 (仅限 Nuxt 3): Nuxt 3 提供了一个 server 目录,里面的文件会被自动注册为 API 路由和服务器中间件。

服务器中间件的执行顺序

服务器中间件的执行顺序很重要,它决定了你的逻辑是否能正确执行。一般来说,执行顺序是按照它们在 nuxt.config.js 中注册的顺序来的。 注意,modules 选项注册的中间件,执行顺序取决于模块本身的实现。

服务器中间件的应用场景

服务器中间件可以做很多事情,比如:

  • 日志记录: 记录每次请求的信息,方便调试和分析。
  • 权限认证: 检查用户是否登录,是否有权限访问某些资源。
  • API 代理: 将客户端的 API 请求代理到后端的 API 服务器。
  • 数据缓存: 将一些数据缓存到服务器端,减少数据库的压力。
  • 重定向: 将某些 URL 重定向到其他 URL。
  • 修改请求/响应: 修改请求头、请求体,或者响应头、响应体。

实战演练:API 请求处理

假设我们需要做一个博客系统,需要从后端的 API 服务器获取文章列表。我们可以使用服务器中间件来代理 API 请求。

  1. 安装 @nuxtjs/axios 模块:

    npm install @nuxtjs/axios
    # 或者
    yarn add @nuxtjs/axios
  2. 配置 @nuxtjs/axios 模块:

    // nuxt.config.js
    export default {
      modules: [
        '@nuxtjs/axios'
      ],
      axios: {
        baseURL: 'https://your-api-server.com' // 你的 API 服务器地址
      }
    }
  3. 创建服务器中间件 ~/server-middleware/api.js:

    // ~/server-middleware/api.js
    import axios from 'axios'
    
    export default async function (req, res) {
      const { url, method, headers, body } = req;
    
      try {
        const response = await axios({
          method: method,
          url: url.replace('/api', ''), // 去掉 /api 前缀
          baseURL: 'https://your-api-server.com', // 确保 baseURL 正确
          headers: {
            ...headers,
            host: 'your-api-server.com' // 修正 host 头,防止跨域问题
          },
          data: body
        });
    
        res.statusCode = response.status;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify(response.data));
      } catch (error) {
        console.error('API proxy error:', error);
        res.statusCode = error.response?.status || 500;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ message: 'API proxy error', error: error.message }));
      }
    }
  4. 注册服务器中间件:

    // nuxt.config.js
    export default {
      modules: [
        '@nuxtjs/axios'
      ],
      axios: {
        baseURL: 'https://your-api-server.com'
      },
      serverMiddleware: [
        { path: '/api', handler: '~/server-middleware/api' }
      ]
    }

现在,当你在客户端发起 /api/articles 请求时,Nuxt.js 会将请求代理到 https://your-api-server.com/articles

代码解释:

  • import axios from 'axios':导入 axios 库,用于发起 HTTP 请求。
  • req.url.replace('/api', ''):去掉请求 URL 中的 /api 前缀,因为 API 服务器不需要这个前缀。
  • baseURL: 'https://your-api-server.com':设置 axiosbaseURL,确保请求发送到正确的 API 服务器。
  • headers: { ...headers, host: 'your-api-server.com' }:将客户端的请求头传递给 API 服务器,并且修正 host 头,防止跨域问题。
  • data: body:将客户端的请求体传递给 API 服务器。
  • res.statusCode = response.status:将 API 服务器的响应状态码传递给客户端。
  • res.setHeader('Content-Type', 'application/json'):设置响应头的 Content-Typeapplication/json
  • res.end(JSON.stringify(response.data)):将 API 服务器的响应数据以 JSON 格式返回给客户端。
  • 错误处理:捕获 axios 请求的错误,并将错误信息返回给客户端。

实战演练:权限认证

假设我们需要对某些 API 接口进行权限认证,只有登录用户才能访问。我们可以使用服务器中间件来检查用户的登录状态。

  1. 安装 cookie-universal-nuxt 模块:

    npm install cookie-universal-nuxt
    # 或者
    yarn add cookie-universal-nuxt
  2. 配置 cookie-universal-nuxt 模块:

    // nuxt.config.js
    export default {
      modules: [
        'cookie-universal-nuxt'
      ],
      // 可选配置
      cookie: {
        options: {
          // 设置 cookie 的默认选项
          expires: 7 // 7 天过期
        }
      }
    }
  3. 创建服务器中间件 ~/server-middleware/auth.js:

    // ~/server-middleware/auth.js
    export default function (req, res, next) {
      const token = req.headers.cookie ? req.headers.cookie.replace(/(?:(?:^|.*;s*)tokens*=s*([^;]*).*$)|^.*$/, "$1") : null; // 从 cookie 中获取 token
    
      if (!token) {
        res.statusCode = 401;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ message: 'Unauthorized' }));
        return;
      }
    
      // 验证 token 的有效性 (这里只是一个简单的例子,实际项目中需要更严谨的验证)
      if (token !== 'valid_token') {
        res.statusCode = 403;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ message: 'Forbidden' }));
        return;
      }
    
      // 如果 token 有效,则继续执行下一个中间件
      next();
    }
  4. 注册服务器中间件:

    // nuxt.config.js
    export default {
      modules: [
        'cookie-universal-nuxt'
      ],
      serverMiddleware: [
        { path: '/api/admin', handler: '~/server-middleware/auth' } // 只有访问 /api/admin 开头的接口才会进行权限认证
      ]
    }

现在,当用户访问 /api/admin/articles 接口时,Nuxt.js 会先执行 auth 中间件,检查用户的登录状态。如果用户未登录或者 token 无效,则会返回 401 或者 403 错误。

代码解释:

  • req.headers.cookie:获取请求头中的 cookie
  • req.headers.cookie.replace(/(?:(?:^|.*;s*)tokens*=s*([^;]*).*$)|^.*$/, "$1"): 使用正则表达式从 cookie 中提取名为 token 的 cookie 值。如果找不到,则返回 null
  • token !== 'valid_token':这里只是一个简单的例子,实际项目中需要使用更严谨的方式来验证 token 的有效性,比如使用 JWT (JSON Web Token)。

服务器中间件的注意事项

  • 性能: 服务器中间件会增加服务器的负担,所以要尽量减少中间件的数量和复杂度。
  • 错误处理: 一定要做好错误处理,防止中间件出错导致整个应用崩溃。
  • 安全: 要注意安全问题,防止中间件被恶意利用。
  • 调试: 可以使用 console.log 来调试中间件,或者使用 Node.js 的调试工具。

Nuxt 3 的新特性

Nuxt 3 对服务器中间件进行了改进,主要有以下几点:

  • server 目录: Nuxt 3 提供了一个 server 目录,里面的文件会被自动注册为 API 路由和服务器中间件。
  • API 路由:server/api 目录下创建的文件会被自动注册为 API 路由,你可以直接在里面编写 API 逻辑,无需手动注册中间件。
  • 类型安全: Nuxt 3 使用 TypeScript 编写,可以提供更好的类型安全。

表格总结

功能 描述
日志记录 记录每次请求的信息,方便调试和分析。
权限认证 检查用户是否登录,是否有权限访问某些资源。
API 代理 将客户端的 API 请求代理到后端的 API 服务器。
数据缓存 将一些数据缓存到服务器端,减少数据库的压力。
重定向 将某些 URL 重定向到其他 URL。
修改请求/响应 修改请求头、请求体,或者响应头、响应体。
性能 服务器中间件会增加服务器的负担,所以要尽量减少中间件的数量和复杂度。
错误处理 一定要做好错误处理,防止中间件出错导致整个应用崩溃。
安全 要注意安全问题,防止中间件被恶意利用。

结束语

好了,今天的讲座就到这里。希望大家对 Nuxt.js 的服务器中间件有了更深入的了解。记住,服务器中间件是一个强大的工具,可以帮助你处理很多服务器端的逻辑。但是,也要注意性能、安全等问题。下课!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注