Next.js第十章(Proxy)

Proxy代理

从 Next.js 16 开始,中间件Middleware更名为代理(Proxy),以更好地体现其用途。其功能保持不变

如果你想升级为16.x版本,Next.js提供了命令行工具来帮助你升级,只需要执行以下命令即可:

bash 复制代码
npx @next/codemod@canary middleware-to-proxy .

代码转换会将文件和函数名从middleware重命名为proxy。

ts 复制代码
// middleware.ts -> proxy.ts
 
- export function middleware() {
+ export function proxy() {

基本使用

应用场景:

  • 处理跨域请求
  • 接口转发例如/api/user -> (可能是其他服务器java/go/python等) -> /api/user
  • 限流例如配合第三方服务做限流
  • 鉴权/判断是否登录

Prxoy代理其实跟拦截器类似,它可以在请求完成之前进行拦截,然后进行一些处理,例如:修改请求头、修改请求体、修改响应体等。

src/proxy.ts

定义proxy函数导出即可,Next.js会自动调用这个函数。

ts 复制代码
import { NextRequest, NextResponse } from "next/server";
export async function proxy(request: NextRequest) {
    console.log(request.url,'url');
}

但是你会发现,他会拦截项目中所有的请求,包括静态资源、API请求、页面请求等。

txt 复制代码
http://localhost:3000/.well-known/appspecific/com.chrome.devtools.json url
http://localhost:3000/_next/static/chunks/src_app_globals_91e4631d.css url
http://localhost:3000/_next/static/chunks/%5Bturbopack%5D_browser_dev_hmr-client_hmr-client_ts_cedd0592._.js url
http://localhost:3000/_next/static/chunks/node_modules_next_dist_compiled_react-dom_1e674e59._.js url
http://localhost:3000/_next/static/chunks/node_modules_next_dist_compiled_react-server-dom-turbopack_9212ccad._.js url
http://localhost:3000/_next/static/chunks/node_modules_next_dist_compiled_next-devtools_index_1dd7fb59.js url
http://localhost:3000/_next/static/chunks/node_modules_next_dist_compiled_a0e4c7b4._.js url
http://localhost:3000/_next/static/chunks/node_modules_next_dist_client_a38d7d69._.js url
http://localhost:3000/_next/static/chunks/node_modules_next_dist_4b2403f5._.js url
http://localhost:3000/_next/static/chunks/src_app_globals_91e4631d.css.map url
http://localhost:3000/_next/static/chunks/node_modules_%40swc_helpers_cjs_d80fb378._.js url
http://localhost:3000/_next/static/chunks/_a0ff3932._.js url
http://localhost:3000/api/login url

配置(config)

例如我们只想匹配'/api'下面的路径去做一些事情,我们可以使用config配置来实现。

ts 复制代码
import { NextRequest, NextResponse } from "next/server";
export async function proxy(request: NextRequest) {
    console.log(request.url,'url');
}
//配置匹配路径
export const config = {
    matcher: '/api/:path*',
    //matcher: ['/api/:path*','/api/user/:path*'], 支持单个以及多个路径匹配
    //matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'], 同样支持正则表达式匹配
}

结合之前的案例,在cookie那一集,我们还需要单独定义check接口检查cookie,现在我们可以直接在proxy中实现。

ts 复制代码
import { NextRequest, NextResponse } from "next/server";
export async function proxy(request: NextRequest) {
    const cookie = request.cookies.get('token');
    if (request.nextUrl.pathname.startsWith('/home') && !cookie) {
        console.log('redirect to login');
        return NextResponse.redirect(new URL('/', request.url));
    }
    if (cookie && cookie.value) {
        return NextResponse.next();
    }
    return NextResponse.redirect(new URL('/', request.url));
}

export const config = {
    matcher: ['/api/:path*', '/home/:path*'],
}

复杂匹配

  • source: 表示匹配路径
  • has: 表示匹配路径中必须(包含)某些条件
  • missing: 表示匹配路径中(必须不包含)某些条件

type 只能匹配: header, query, cookie

ts 复制代码
import { NextRequest, NextResponse } from "next/server";
import { ProxyConfig } from "next/server";
export async function proxy(request: NextRequest) {
   console.log('start proxy')
   return NextResponse.next();
}

export const config: ProxyConfig = {
    matcher: [
        {
            source: '/home/:path*',
            //表示匹配路径中必须(包含)Authorization头和userId查询参数
            has: [
                { type: 'header', key: 'Authorization', value: 'Bearer 123456' },
                { type: 'query', key: 'userId', value: '123' }
            ],
            //表示匹配路径中(必须不包含)cookie和userId查询参数
            missing: [
                { type: 'cookie', key: 'token', value: '123456' },
                { type: 'query', key: 'userId', value: '456' },
            ]
        },
    ]
}

访问url为:http://localhost:3000/home?userId=123

案例实战(处理跨域)

只要是/api下面的接口都可以被任意访问

ts 复制代码
import { NextRequest, NextResponse } from "next/server";
import { ProxyConfig } from "next/server";
export async function proxy(request: NextRequest) {
    const response = NextResponse.next();
    Object.entries(corsHeaders).forEach(([key, value]) => {
        response.headers.set(key, value);
    })
    return response;
}

const corsHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
}

export const config: ProxyConfig = {
   matcher:'/api/:path*',
}
相关推荐
d***9353 小时前
Webpack、Vite区别知多少?
前端·webpack·node.js
清风徐来QCQ3 小时前
javaScript(map,ref,?,forEach,watch)
java·前端·javascript
q***73553 小时前
windows配置永久路由
android·前端·后端
前端布鲁伊3 小时前
再来聊聊,Vue3 项目中 Pinia 的替代方案
前端·面试
柒昀4 小时前
Vue.js
前端·javascript·vue.js
2201_757830874 小时前
Stream的终结方法
java·服务器·前端
进阶的鱼4 小时前
React+ts+vite脚手架搭建(五)【登录篇】
前端·javascript
safestar20124 小时前
React深度实战:从组件抽象到性能优化的思考历程
前端·javascript·react.js
洗澡水加冰4 小时前
VSCode插件: 自动临时分配Theme以区分不同窗口
前端·typescript·visual studio code