本文概括:
- 在 Next.js 中定义 GET/POST 接口及动态路由、缓存控制。
middleware.ts
用法,包括重定向、Cookie、请求/响应头、CORS 设置。- 环境变量用法及前端访问前缀
NEXT_PUBLIC_
。 next.config.js
配置技巧,如代理、图片优化、构建检查和输出模式。
接口
Next.js里可以直接写后端接口:nextjs.org/docs/app/ap...
一般接口会放在 app/api/xxx/route.ts
文件里
在 app/api/test/route.ts
中:
javascript
import { NextResponse, type NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const res = {
code: 0,
message: 'Hello, world!',
data: {
name: 'cxk',
},
}
return NextResponse.json(res)
}
这样就可以定义一个GET接口,接口接受的参数如下:
javascript
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
// 访问/test页面,返回 /test
const pathname = request.nextUrl.pathname
// 访问/test?name=cxk页面,返回 {name: 'cxk'}
const searchParams = request.nextUrl.searchParams
const res = {
code: 0,
message: 'Hello, world!',
data: {
name: searchParams.get('name'),
pathname: pathname,
},
}
return NextResponse.json(res)
}
具体内容可以看:nextjs.org/docs/app/ap...
第二个参数是context,取决于动态路由当前的route
例如如果新建 app/test/[id]/route.ts
那么就可以从这里拿到id了
缓存问题:
默认情况下,如果GET接口会缓存,如果使用了Request对象,或者POST接口,那么就不会缓存了,如果设置了:
dart
// 强制为动态渲染
export const dynamic = 'force-dynamic'
// 置重新验证频率为 10s , 在10s之后第一次访问开始过期数据,第二次访问拿到新的数据
export const revalidate = 10
中间件
参考地址:nextjs.org/docs/app/ap...
中间件可以拦截请求和响应,做登录鉴权等很多事情
在 app
同级目录中定义一个 middleware.ts
文件
javascript
import { NextRequest, NextResponse } from 'next/server'
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/', request.url))
}
export const config = {
matcher: '/test/:path*',
}
如上代码,可以将 /test/xxx
重新向到 /
Cookie操作:
下面是Next.js文档对Cookie的操作,可以使用 NextResponse.next()
拿到Response,最后需要返回
javascript
// This function can be marked `async` if using `await` inside
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
}
Header操作:
可以对请求头进行一些操作:
javascript
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操作:
javascript
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*',
}
环境变量
Next.js的环境变量可以放到 .env*
文件里, .env.local
的优先级最高,例如文件内容:
ini
DB_HOST=localhost
DB_USER=myuser
DB_PASS=mypassword
使用的时候:
arduino
export async function GET() {
const db = await myDB.connect({
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS,
})
// ...
}
默认的变量都应该是在后端使用的,如果需要浏览器也可以使用,那么需要加前缀: NEXT_PUBLIC_
,有这个前缀的会被浏览器使用。
ini
NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk
配置
Next.js 可以通过根目录的 next.config.js
进行配置:
官方文档:nextjs.org/docs/app/ap...
比较有用的几个配置技巧:
代理:
javascript
rewrites: async () => {
if (process.env.NODE_ENV !== "development") {
console.log("Not in development mode, skipping rewrites");
return [];
}
return [
{
source: "/api/:path*",
destination: `${apiUrl}/:path*`,
},
];
},
禁用图片优化:
yaml
images: {
unoptimized: true, // 禁用优化
},
构建禁用ts和eslint检查:
yaml
eslint: {
ignoreDuringBuilds: true,
},
typescript: {
ignoreBuildErrors: true,
},
构建是否需要后端:
arduino
output: "standalone", // 不需要后端,就用 export 静态页面即可, 需要后端,就standalone