heky 发布的文章

很久不进行写作的我,渐渐失去了写作的能力。
我会回忆起高一的时候,我们语文老师让我们写周记。
我的分享欲或许就是在那个时候培养起来的。后来到了博客。
总是会在有节日的时候送上祝福,好像真的有人在关注一样。
悲观的情感总是促使写作的原因。
或许也是促使分享的原因。
我认为我在上了大学之后生活逐渐的变好了。
或许是因为有了更需要关注的事情,让我渐渐的不再有分享的心。
又或者是因为和周围人能够交流的机会变得很少了。
就算是上课,大家也基本上不会有互动。
少数的时候不得已必须要交流的时候,也会交流一二,等下了课之后就又散了。
因为这种不固定的地缘关系。
让被迫进行的交流变得少了,我可以把更多的精力放在其他的地方。
不管是什么地方,总归不再是人际交往方面。
事实上这也是我高中时候就一直在期待的。

如果希望在 Next.js 的服务端组件(Server Component)中获取当前请求的路径(pathname),但又不想使用 API 路由或客户端组件(Client Component),可以通过使用 Middleware 来实现。

使用 Middleware 获取当前路径

可以在 Next.js 的 Middleware 中拦截请求,并将当前路径添加到请求头中,然后在服务端组件中读取该请求头,从而获取当前路径。

1. 创建 Middleware

在项目的根目录下创建一个 middleware.ts 文件:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-current-path', request.nextUrl.pathname);

  return NextResponse.next({
    request: {
      headers: requestHeaders,
    },
  });
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

上述 Middleware 会将当前请求的路径添加到请求头中的 x-current-path 字段。(Medium)

2. 在服务端组件中读取路径

在服务端组件中,可以使用 headers() 方法读取请求头,从而获取当前路径:(propelauth.com)

import { headers } from 'next/headers';
export default async function Getsuffix(layer : number):Promise<string>{
  const headerList = await headers();
  const pathname = headerList.get('x-current-path') || '/';
  // 解析路径后缀
  const segments = pathname.split('/');
  const titleSuffix = segments[layer] || '';
  return (
    titleSuffix
  );
}

在构建中大型的 Next.js 应用时,我们往往需要在请求进入应用之前做一些预处理,比如用户认证、国际化设置、重定向等。Next.js 从 12 版本开始支持 Middleware,它运行于边缘节点,可以在请求到达页面组件之前拦截和处理请求。

本文将逐步讲解如何在 Next.js 中实现多个中间件的逻辑,并且保持代码的清晰与模块化。


一、Middleware 的基础概念

在 Next.js 中,你只需要在项目根目录创建一个名为 middleware.tsmiddleware.js 的文件即可启用 Middleware。这个文件会自动被 Next.js 识别,不需要额外配置。

一个最基础的中间件看起来如下:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  return NextResponse.next();
}

该中间件会对所有请求生效,并简单地允许请求继续往下走。


二、实现多个中间件逻辑的需求

假设我们现在有两个独立的功能需要处理:

  1. authMiddleware: 用于判断用户是否登录,未登录则重定向到 /login
  2. i18nMiddleware: 用于设置用户语言偏好

我们希望它们都在每个请求前依次执行。如何做到这点呢?


三、模块化中间件逻辑

为了保持代码整洁,我们将每个功能模块拆分到单独文件中:

middlewares/authMiddleware.ts

import { NextRequest, NextResponse } from 'next/server';

export function authMiddleware(request: NextRequest): NextResponse | void {
  const isAuthenticated = true; // 示例逻辑
  if (!isAuthenticated) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
}

middlewares/i18nMiddleware.ts

import { NextRequest, NextResponse } from 'next/server';

export function i18nMiddleware(request: NextRequest): NextResponse | void {
  const locale = request.headers.get('accept-language')?.split(',')[0] || 'en';
  request.headers.set('x-locale', locale);
}

四、在 middleware.ts 中组合这些中间件

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { authMiddleware } from './middlewares/authMiddleware';
import { i18nMiddleware } from './middlewares/i18nMiddleware';

export function middleware(request: NextRequest): NextResponse {
  const authResponse = authMiddleware(request);
  if (authResponse) return authResponse;

  const i18nResponse = i18nMiddleware(request);
  if (i18nResponse) return i18nResponse;

  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

我们依次执行每一个中间件函数:

  • 如果某个中间件返回了 NextResponse,表示它希望拦截或终止请求流程,例如重定向;
  • 如果返回 undefined,表示它只是修改了请求状态或头部,不影响流程,继续执行下一个。

这种模式非常直观,也方便调试和扩展。


五、为什么使用 return 会中止后续中间件?

很多开发者初看可能会疑惑:

"既然我要执行多个中间件,为什么用 return 会跳过后面的逻辑?"

这是因为我们在实现“链式中间件”的处理逻辑——每个中间件有权决定是否终止请求流程。

举例来说,用户未认证时我们希望立即重定向到 /login,那么其他逻辑(比如设置语言、加载用户数据)就不需要再执行。

这种设计思路与很多后端框架如 Express.js 的中间件模型类似。


六、总结

Next.js 的 Middleware 是一个强大且灵活的工具,允许你在请求生命周期的早期阶段拦截和处理逻辑。

  • 你只需一个 middleware.ts 文件
  • 将每个中间件功能模块化,方便复用与测试
  • 在主中间件函数中按顺序调用它们,并根据是否返回 NextResponse 控制流程

这样的设计既保持了结构的清晰,又便于日后扩展。如果你在构建应用时需要实现用户权限、国际化、AB 测试等功能,Middleware 是一个值得深入使用的机制。

希望本文对你理解和使用 Next.js Middleware 有所帮助!