likes
comments
collection
share

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

作者站长头像
站长
· 阅读数 45

一、路由(以App Router为例):

1.Nextjs使用项目目录结构去定义路由:

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

在对应路由文件夹下:

  • page.js文件定义页面
  • layout.js处理布局(page的内容会作为layout的children传入)
  • template.js(模板的路由之间导航时,会重新挂载children的新实例,创建 DOM 元素,不hi像布局一样维持状态)

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

其他特殊页面: loading 展示loading、 error 展示错误等

2.重定向API

参考 Routing: Redirecting | Next.js (nextjs.org)

3.路由组

可以将项目文件按照一定逻辑去分组,同时避免影响页面路径:

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

4.平行路由

平行路由功能以插槽方式使用

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

其有如下使用方式:

  • 在layout内部有条件的显示页面

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

  • 允许为每个路由定义独立错误和加载页面

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

  • 插槽内添加子页面方便创建标签页组

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

import Link from 'next/link'
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <>
      <nav>
        <Link href="/page-views">Page Views</Link>
        <Link href="/visitors">Visitors</Link>
      </nav>
      <div>{children}</div>
    </>
  )
}

5.拦截路由

拦截路由时需要处理文件夹命名:

  • (.) 匹配同一层级
  • (..) 匹配上一层级
  • (..)(..) 匹配上上层级。
  • (...) 匹配根目录app

二、路由处理程序(以路由方式处理请求和响应):

路由处理程序需要名为router的文件,并且要在app目录下, 但是不能和page文件同目录: 支持这些HTTP方法:GETPOSTPUTPATCHDELETEHEADOPTIONS

1.路由处理程序的一些行为:

Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定

2.使用例子:

  • 可以使用增量静态重新生成 (ISR): 重新验证缓存的数据
  • Cookie:
    • 获取请求Cookie:
    // app/api/route.js 
    export async function GET(request) { 
        const token = request.cookies.get('token') 
        request.cookies.set(`token2`, 123) 
    }
    
    • 设置响应Cookie:
    // app/api/route.js
        import { cookies } from 'next/headers'
    
        export async function GET(request) {
          const cookieStore = cookies()
          const token = cookieStore.get('token')
    
          return new Response('Hello, Next.js!', {
            status: 200,
            headers: { 'Set-Cookie': `token=${token}` },
          })
        }
    
    
  • Header
    • 使用next/headers
    import { headers } from 'next/headers'
    
        export async function GET(request: Request) {
          const headersList = headers()
          const referer = headersList.get('referer')
    
          return new Response('Hello, Next.js!', {
            status: 200,
            headers: { referer: referer },
          })
        }
    
    // app/api/route.js
        export async function GET(request) {
          const headersList = new Headers(request.headers)
          const referer = headersList.get('referer')
        }
    
  • 重定向
    import { redirect } from 'next/navigation' 
    export async function GET(request: Request) { 
        redirect('https://nextjs.org/')
    }
    
  • 获取动态路由值 Nextjs 构建应用基础: 路由和中间件一、路由(以App Router为例): 1.Nextjs使用项目目录结构去定
export async function GET(
  request: Request,
  { params }: { params: { slug: string } }
) {
  const slug = params.slug // 'a', 'b', or 'c'
}
  • 获取URL请求参数
import { type NextRequest } from 'next/server'
 
export function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams
  const query = searchParams.get('query')
  // query is "hello" for /api/search?query=hello
}
  • 支持流式处理 流式处理
  • 获取请求体
    // 普通请求体
    export async function POST(request: Request) {
    const res = await request.json()
    return Response.json({ res })
    
    // formData
    export async function POST(request: Request) {
    const formData = await request.formData()
    const name = formData.get('name')
    const email = formData.get('email')
    return Response.json({ name, email })
    
  • 设置CORS
    export async function GET(request: Request) {
    return new Response('Hello, Next.js!', {
    status: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
    })
    
  • 非UI内容返回
    export async function GET() {
          return new Response(
            `<?xml version="1.0" encoding="UTF-8" ?>
        <rss version="2.0">
    
        <channel>
          <title>Next.js Documentation</title>
          <link>https://nextjs.org/docs</link>
          <description>The React Framework for the Web</description>
        </channel>
    
        </rss>`,
            {
              headers: {
                'Content-Type': 'text/xml',
              },
            }
          )
    }
    

三、中间件

使用中间件可以拦截和处理应用中的请求和响应: 其应用场景包括:身份验证和授权服务器端重定向路径重写,爬虫程序检测,日志记录和分析,功能标记等;

1.定义中间件

在项目的根目录定义 middleware文件,例子如下:

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}
 
// See "Matching Paths" below to learn more
export const config = {
  matcher: '/about/:path*',
}

上面将/about/路径重定向到home路径下

3.注意路由响应过程中对应配置的执行顺序

  1. headers(next.config.js
  2. redirects(next.config.js
  3. 中间件 (rewritesredirects 等)
  4. beforeFiles(next.config.jsrewrites)
  5. 文件系统的路由 (public/_next/static/pages/app/ )
  6. afterFiles (next.config.jsrewrites)
  7. 动态路由 (/blog/[slug])
  8. fallback (next.config.jsrewrites)

2.路径匹配器

  • 匹配单一路径或多个路径
export const config = {
  matcher: '/about/:path*',
  matcher: ['/about/:path*', '/dashboard/:path*'],
}
  • 使用条件语句
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))
  }
}

3.可以执行的操作

  • 使用NextResponse处理响应
  • 对Cookie的读取和处理:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
export function middleware(request: NextRequest) {
  // Assume a "Cookie:nextjs=fast" header to be present on the incoming request
  // Getting cookies from the request using the `RequestCookies` API
  let cookie = request.cookies.get('nextjs')
  console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
  const allCookies = request.cookies.getAll()
  console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]
 
  request.cookies.has('nextjs') // => true
  request.cookies.delete('nextjs')
  request.cookies.has('nextjs') // => false
 
  // Setting cookies on the response using the `ResponseCookies` API
  const response = NextResponse.next()
  response.cookies.set('vercel', 'fast')
  response.cookies.set({
    name: 'vercel',
    value: 'fast',
    path: '/',
  })
  cookie = response.cookies.get('vercel')
  console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
  // The outgoing response will have a `Set-Cookie:vercel=fast;path=/` header.
 
  return response
}
  • 设置请求和响应头
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
export function middleware(request: NextRequest) {
  // Clone the request headers and set a new header `x-hello-from-middleware1`
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-hello-from-middleware1', 'hello')
 
  // You can also set request headers in NextResponse.next
  const response = NextResponse.next({
    request: {
      // New request headers
      headers: requestHeaders,
    },
  })
 
  // Set a new response header `x-hello-from-middleware2`
  response.headers.set('x-hello-from-middleware2', 'hello')
  return response
}
  • 设置CORS
import { NextRequest, NextResponse } from 'next/server'
 
const allowedOrigins = ['https://acme.com', 'https://my-app.org']
 
const corsOptions = {
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization',
}
 
export function middleware(request: NextRequest) {
  // Check the origin from the request
  const origin = request.headers.get('origin') ?? ''
  const isAllowedOrigin = allowedOrigins.includes(origin)
 
  // Handle preflighted requests
  const isPreflight = request.method === 'OPTIONS'
 
  if (isPreflight) {
    const preflightHeaders = {
      ...(isAllowedOrigin && { 'Access-Control-Allow-Origin': origin }),
      ...corsOptions,
    }
    return NextResponse.json({}, { headers: preflightHeaders })
  }
 
  // Handle simple requests
  const response = NextResponse.next()
 
  if (isAllowedOrigin) {
    response.headers.set('Access-Control-Allow-Origin', origin)
  }
 
  Object.entries(corsOptions).forEach(([key, value]) => {
    response.headers.set(key, value)
  })
 
  return response
}
 
export const config = {
  matcher: '/api/:path*',
}
  • 直接生成一个响应
import type { NextRequest } from 'next/server'
import { isAuthenticated } from '@lib/auth'
 
// Limit the middleware to paths starting with `/api/`
export const config = {
  matcher: '/api/:function*',
}
 
export function middleware(request: NextRequest) {
  // Call our authentication function to check the request
  if (!isAuthenticated(request)) {
    // Respond with JSON indicating an error message
    return Response.json(
      { success: false, message: 'authentication failed' },
      { status: 401 }
    )
  }
}
  • 延长中间件的生命周期 类似await
import { NextResponse } from 'next/server'
import type { NextFetchEvent, NextRequest } from 'next/server'
 
export function middleware(req: NextRequest, event: NextFetchEvent) {
  event.waitUntil(
    fetch('https://my-analytics-platform.com', {
      method: 'POST',
      body: JSON.stringify({ pathname: req.nextUrl.pathname }),
    })
  )
 
  return NextResponse.next()
}

总结

在Next.js中,路由和中间件是构建应用的关键概念。通过App Directory,Next.js提供了灵活的路由系统,支持定义页面、布局和模板。平行路由允许开发者在同一个布局中同时或条件性地渲染多个页面,非常适合动态应用场景,如仪表板。路由处理程序则允许开发者在app目录下创建自定义的请求处理逻辑,支持多种HTTP方法,并能利用Next.js提供的扩展API。

中间件则为应用提供了在请求到达页面或API之前进行拦截和处理的能力,适用于身份验证、重定向、CORS设置等多种场景。开发者可以通过定义middleware.js文件来创建中间件,并利用Next.js提供的API进行复杂的请求处理。

转载自:https://juejin.cn/post/7413682017298858018
评论
请登录