我正在使用 Next.js 13,并且为多语言设置了中间件功能。我想添加另一个中间件功能,但它对我不起作用。我想我在编写中间件时犯了一个错误,但我不确定在哪里。我没有收到任何错误,它只是不起作用。
这是我的代码:
import { NextResponse, NextRequest } from 'next/server'
import acceptLanguage from 'accept-language'
import { fallbackLng, languages } from './app/i18n/settings'
acceptLanguage.languages(languages)
const cookieName = 'i18next'
export function middleware(req: any) {
let lng
if (req.cookies.has(cookieName)) lng = acceptLanguage.get(req.cookies.get(cookieName).value)
// automatic detect language with browser
// if (!lng) lng = acceptLanguage.get(req.headers.get('Accept-Language'))
if (!lng) lng = fallbackLng
// Redirect if lng in path is not supported
if (
!languages.some(loc => req.nextUrl.pathname.startsWith(`/${loc}`)) &&
!req.nextUrl.pathname.startsWith('/_next')
) {
return NextResponse.redirect(new URL(`/${lng}${req.nextUrl.pathname}`, req.url))
}
if (req.headers.has('referer')) {
const refererUrl = new URL(req.headers.get('referer'))
const lngInReferer = languages.find((l) => refererUrl.pathname.startsWith(`/${l}`))
const response = NextResponse.next()
if (lngInReferer) response.cookies.set(cookieName, lngInReferer)
return response
}
return NextResponse.next()
}
export function middleware2(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/about')){
return NextResponse.redirect(new URL('/home', request.url))
}
}
export const config = {
api: {
bodyParser: false,
},
matcher: ['/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js).*)']
}
只能导出一个中间件函数。
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/about')) {
return NextResponse.rewrite(new URL('/about-2', request.url))
}
if (request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.rewrite(new URL('/dashboard/user', request.url))
}
}
在您的情况下,您应该将
middleware2
中的条件移至middleware
export function middleware(req: any) {
// From middleware2
if (request.nextUrl.pathname.startsWith('/about')){
return NextResponse.redirect(new URL('/home', request.url))
}
let lng
if (req.cookies.has(cookieName)) lng = acceptLanguage.get(req.cookies.get(cookieName).value)
// automatic detect language with browser
// if (!lng) lng = acceptLanguage.get(req.headers.get('Accept-Language'))
if (!lng) lng = fallbackLng
// Redirect if lng in path is not supported
if (
!languages.some(loc => req.nextUrl.pathname.startsWith(`/${loc}`)) &&
!req.nextUrl.pathname.startsWith('/_next')
) {
return NextResponse.redirect(new URL(`/${lng}${req.nextUrl.pathname}`, req.url))
}
if (req.headers.has('referer')) {
const refererUrl = new URL(req.headers.get('referer'))
const lngInReferer = languages.find((l) => refererUrl.pathname.startsWith(`/${l}`))
const response = NextResponse.next()
if (lngInReferer) response.cookies.set(cookieName, lngInReferer)
return response
}
return NextResponse.next()
}
此外,该配置没有
api
属性。 matcher
属性使您可以选择在特定路由上运行中间件。如果请求路径是 /api
、/_next/static
、/_next/image
、/assets
、/favicon.ico
和 /sw
中的任何一个,下面的配置将阻止中间件运行
export const config = {
matcher: ['/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js).*)']
}
Next.js 在我写这个答案时不支持多个中间件,但您可以通过以下步骤自行处理:
在根目录中创建一个中间件文件夹(如果在 Next.js 中使用则为 src)
使用以下代码在此文件夹中创建 config.ts 文件
import Authentication from "@/middleware/authentication";
import Localization from "@/middleware/localization";
// import Logging from "@/middleware/logging";
export const middleware = [
Authentication,
Localization,
// Logging
// and ...
]
根据需要创建每个中间件。如您所见,我在其目录中添加了身份验证和本地化中间件,每个中间件文件应具有以下结构:
import {NextRequest, NextResponse} from "next/server";
export default async function Authentication(req: NextRequest): Promise<NextResponse> {
// you codes ...
}
import type {NextRequest} from 'next/server'
import {middleware as activatedMiddleware} from '@/middleware/config'
import {NextResponse} from "next/server";
export async function middleware(req: NextRequest) {
// Load middleware functions
const middlewareFunctions = activatedMiddleware.map(fn => fn(req));
// Option 1: Run middleware synchronously
// This allows you to handle each result before moving to the next
/*
for(const fn of middlewareFunctions){
const result = await fn;
if(!result.ok){
return result;
}
}
return NextResponse.next();
*/
// Option 2: Run middleware asynchronously
// Using Promise.allSettled allows concurrent execution
const results = await Promise.allSettled(middlewareFunctions);
// Check each result
for (const result of results) {
// If rejected or not OK, return first response
if (result.status === "fulfilled" && !result.value?.ok) {
return result.value;
} else if (result.status === "rejected") {
throw result.reason
}
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)',],
}
您似乎正在尝试在同一个文件中使用两个中间件函数(middleware 和 middleware2)。但是,Next.js 只允许每个文件导出一个中间件函数。
如果要使用多个中间件函数,则应该为每个中间件函数创建单独的文件。例如,您可以为第一个中间件函数创建一个 middleware1.js 文件,为第二个中间件函数创建一个 middleware2.js 文件。
以下是将中间件函数分成两个文件的方法:
中间件1.js
import { NextResponse, NextRequest } from 'next/server'
import acceptLanguage from 'accept-language'
import { fallbackLng, languages } from './app/i18n/settings'
acceptLanguage.languages(languages)
const cookieName = 'i18next'
export function middleware(req: any) {
let lng
if (req.cookies.has(cookieName)) lng = acceptLanguage.get(req.cookies.get(cookieName).value)
if (!lng) lng = fallbackLng
if (
!languages.some(loc => req.nextUrl.pathname.startsWith(`/${loc}`)) &&
!req.nextUrl.pathname.startsWith('/_next')
) {
return NextResponse.redirect(new URL(`/${lng}${req.nextUrl.pathname}`, req.url))
}
if (req.headers.has('referer')) {
const refererUrl = new URL(req.headers.get('referer'))
const lngInReferer = languages.find((l) => refererUrl.pathname.startsWith(`/${l}`))
const response = NextResponse.next()
if (lngInReferer) response.cookies.set(cookieName, lngInReferer)
return response
}
return NextResponse.next()
}
export const config = {
api: {
bodyParser: false,
},
matcher: ['/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js).*)']
}
中间件2.js
import { NextResponse, NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/about')){
return NextResponse.redirect(new URL('/home', request.url))
}
}
请记住在应用程序的适当位置导入和使用这些中间件函数。