You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13 App Router如何配置API仅允许前端请求访问?

阻止外部请求访问Next.js 13 App目录下的API接口

问题分析

你当前的Middleware判断逻辑request.nextUrl.pathname.startsWith('/api')完全失效——不管是外部curl请求还是前端内部发起的请求,目标路径都是/api/get-token,所以都会返回true。要区分内部和外部请求,需要依赖请求头这类无法轻易伪造(或伪造成本高)的标识。

可行解决方案

方法1:检查Origin/Referer请求头

前端内部发起的请求会自动带上同域的Origin或Referer头,而外部直接请求(比如curl)默认不会携带这些头,或者携带的是其他域的值。

修改后的Middleware代码:

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

enum MiddlewareRoutes {
    GET_TOKEN = '/api/get-token',
}

const middlewareHandler = async (
    route: MiddlewareRoutes,
    request: NextRequest,
    response: NextResponse
): Promise<NextResponse> => {
    switch (route) {
        case MiddlewareRoutes.GET_TOKEN: {
            // 判断是否为内部前端请求
            const origin = request.headers.get('origin');
            const referer = request.headers.get('referer');
            const isLocalOrigin = origin === 'http://localhost:3000'; // 生产环境替换为你的域名
            const isLocalReferer = referer?.startsWith('http://localhost:3000/');
            
            const fromFE = isLocalOrigin || isLocalReferer;
            console.log('From Frontend = ', fromFE);

            // 如果不是内部请求,直接拦截
            if (!fromFE) {
                return new NextResponse('Unauthorized', { status: 401 });
            }

            return response;
        }
        default: {
            return response;
        }
    }
};

export async function middleware(request: NextRequest) {
    const response = NextResponse.next();
    const pathname = request.nextUrl.pathname as MiddlewareRoutes;
    
    // 只处理目标路由,避免不必要的逻辑
    if (Object.values(MiddlewareRoutes).includes(pathname)) {
        return await middlewareHandler(pathname, request, response);
    }
    
    return response;
}

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

方法2:使用Next.js内部请求标识(更可靠)

当客户端组件通过fetch或自定义cacheFetch发起请求时,Next.js会自动添加x-nextjs-data请求头(仅内部请求携带),可以通过检查这个头来判断:

// 替换middlewareHandler里的fromFE判断逻辑
const fromFE = request.headers.get('x-nextjs-data') !== null;
console.log('From Frontend = ', fromFE);

if (!fromFE) {
    return new NextResponse('Unauthorized', { status: 401 });
}

验证效果

  • 用curl http://localhost:3000/api/get-token请求时,日志输出From Frontend = false,且返回401未授权
  • 前端组件通过useEffect发起请求时,日志输出From Frontend = true,正常返回接口数据

内容的提问来源于stack exchange,提问作者Shivam Sahil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:05:24