nextjs 13 应用程序目录中的多个中间件不起作用

问题描述 投票:0回答:3

我正在使用 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).*)']

}

node.js reactjs next.js middleware nextjs13
3个回答
0
投票

只能导出一个中间件函数。

来自 Next.js 13 文档

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).*)']
}

0
投票

Next.js 在我写这个答案时不支持多个中间件,但您可以通过以下步骤自行处理:

  1. 在根目录中创建一个中间件文件夹(如果在 Next.js 中使用则为 src)

  2. 使用以下代码在此文件夹中创建 config.ts 文件

    import Authentication from "@/middleware/authentication";
    import Localization from "@/middleware/localization";
    // import Logging from "@/middleware/logging";
    
    export const middleware = [
        Authentication,
        Localization,
        // Logging
        // and ...
    ]
    
  3. 根据需要创建每个中间件。如您所见,我在其目录中添加了身份验证和本地化中间件,每个中间件文件应具有以下结构:

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

export default async function Authentication(req: NextRequest): Promise<NextResponse> {
  // you codes ...
}
  1. 最后,在项目的根目录中添加一个主 middleware.ts 文件(如文档中所述),其中包含以下内容:
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).*)',],
}

-1
投票

您似乎正在尝试在同一个文件中使用两个中间件函数(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))
  }
}

请记住在应用程序的适当位置导入和使用这些中间件函数。

© www.soinside.com 2019 - 2024. All rights reserved.