各位老铁,晚上好!我是你们的老朋友,代码界的段子手,今天咱们聊聊 Nuxt.js 里的服务器中间件,看看它在 SSR 过程中是怎么耍的。
开场白:SSR 的那些事儿
话说,SSR (Server-Side Rendering,服务端渲染) 这玩意儿,一开始是为了 SEO 优化的,后来发现体验也更好,能更快地看到首屏。但它也有个问题,就是服务器压力大了。Nuxt.js 帮我们简化了 SSR 的流程,但有些逻辑,比如 API 请求、权限认证,还是得我们自己来。这时候,服务器中间件就派上用场了。
什么是 Nuxt.js 服务器中间件?
简单来说,服务器中间件就是一堆函数,它们会在每次请求到达服务器时被执行,可以修改请求、响应,或者直接终止请求。在 Nuxt.js 里,这些中间件运行在 Node.js 环境下,所以你可以访问 Node.js 的所有 API,比如文件系统、数据库等等。
服务器中间件的注册方式
Nuxt.js 提供了几种注册服务器中间件的方式:
-
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(); } ] }
-
modules
选项 (配合模块使用): 有些 Nuxt.js 模块会自带服务器中间件,比如@nuxtjs/axios
,它会帮你代理 API 请求。 -
server
目录 (仅限 Nuxt 3): Nuxt 3 提供了一个server
目录,里面的文件会被自动注册为 API 路由和服务器中间件。
服务器中间件的执行顺序
服务器中间件的执行顺序很重要,它决定了你的逻辑是否能正确执行。一般来说,执行顺序是按照它们在 nuxt.config.js
中注册的顺序来的。 注意,modules
选项注册的中间件,执行顺序取决于模块本身的实现。
服务器中间件的应用场景
服务器中间件可以做很多事情,比如:
- 日志记录: 记录每次请求的信息,方便调试和分析。
- 权限认证: 检查用户是否登录,是否有权限访问某些资源。
- API 代理: 将客户端的 API 请求代理到后端的 API 服务器。
- 数据缓存: 将一些数据缓存到服务器端,减少数据库的压力。
- 重定向: 将某些 URL 重定向到其他 URL。
- 修改请求/响应: 修改请求头、请求体,或者响应头、响应体。
实战演练:API 请求处理
假设我们需要做一个博客系统,需要从后端的 API 服务器获取文章列表。我们可以使用服务器中间件来代理 API 请求。
-
安装
@nuxtjs/axios
模块:npm install @nuxtjs/axios # 或者 yarn add @nuxtjs/axios
-
配置
@nuxtjs/axios
模块:// nuxt.config.js export default { modules: [ '@nuxtjs/axios' ], axios: { baseURL: 'https://your-api-server.com' // 你的 API 服务器地址 } }
-
创建服务器中间件
~/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 })); } }
-
注册服务器中间件:
// 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'
:设置axios
的baseURL
,确保请求发送到正确的 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-Type
为application/json
。res.end(JSON.stringify(response.data))
:将 API 服务器的响应数据以 JSON 格式返回给客户端。- 错误处理:捕获
axios
请求的错误,并将错误信息返回给客户端。
实战演练:权限认证
假设我们需要对某些 API 接口进行权限认证,只有登录用户才能访问。我们可以使用服务器中间件来检查用户的登录状态。
-
安装
cookie-universal-nuxt
模块:npm install cookie-universal-nuxt # 或者 yarn add cookie-universal-nuxt
-
配置
cookie-universal-nuxt
模块:// nuxt.config.js export default { modules: [ 'cookie-universal-nuxt' ], // 可选配置 cookie: { options: { // 设置 cookie 的默认选项 expires: 7 // 7 天过期 } } }
-
创建服务器中间件
~/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(); }
-
注册服务器中间件:
// 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 的服务器中间件有了更深入的了解。记住,服务器中间件是一个强大的工具,可以帮助你处理很多服务器端的逻辑。但是,也要注意性能、安全等问题。下课!