Next.js+React项目中如何禁止用户直接通过URL访问指定路由?
限制Next.js中/checkout系列路由的直接访问方法
方案1:通过会话状态追踪导航流程
核心思路是给用户会话标记「是否完成前置导航步骤」,只有当用户从允许的页面(比如购物车页)跳转过来时,才放行访问/checkout或/checkout/success。
以Pages Router为例:
- 在购物车页面(
/cart)添加状态标记,用户进入时在Cookie或localStorage存入标识:
// pages/cart.js import { useEffect } from 'react'; export default function Cart() { useEffect(() => { // 用Cookie更适合服务端校验,避免localStorage的跨标签页问题 document.cookie = "allowedCheckout=true; path=/; max-age=3600"; }, []); return <div>购物车页面</div>; }
- 在/checkout页面通过服务端函数校验标识,不满足则重定向:
// pages/checkout.js export async function getServerSideProps(context) { const allowed = context.req.cookies.allowedCheckout === 'true'; if (!allowed) { return { redirect: { destination: '/cart', permanent: false, }, }; } // 校验通过后清除标识,防止重复利用 context.res.setHeader('Set-Cookie', 'allowedCheckout=; Path=/; Max-Age=0'); return { props: {} }; } export default function Checkout() { return <div>结算页面</div>; }
如果用App Router(Next.js 13+),可以在Server Component中用cookies()函数做校验,逻辑和上面一致。
方案2:用Next.js中间件拦截非法请求
通过中间件拦截所有/checkout开头的路由,检查请求的Referer头,判断是否来自站内的前置页面。注意:Referer可能被浏览器隐私策略禁用,建议和方案1结合使用。
// middleware.js import { NextResponse } from 'next/server'; export function middleware(request) { const path = request.nextUrl.pathname; if (path.startsWith('/checkout')) { const referer = request.headers.get('referer'); // 校验来源是否为本站的购物车页面 if (!referer || !referer.includes(`${request.nextUrl.origin}/cart`)) { return NextResponse.redirect(new URL('/cart', request.nextUrl)); } } return NextResponse.next(); } export const config = { matcher: ['/checkout/:path*'], };
方案3:客户端路由跳转时传递校验状态
使用next/link或useRouter跳转时,通过state传递校验信息,在/checkout页面检查状态是否存在:
// 购物车页面的跳转代码 import Link from 'next/link'; <Link href="/checkout" state={{ allowed: true }} > 前往结算 </Link> // pages/checkout.js的客户端校验 import { useRouter } from 'next/router'; import { useEffect } from 'react'; export default function Checkout() { const router = useRouter(); useEffect(() => { // 直接访问时state不存在,触发重定向 if (!router.state?.allowed) { router.push('/cart'); } }, [router]); return <div>结算页面</div>; }
⚠️ 注意:客户端校验可以被篡改绕过,优先选择服务端校验方式(方案1的getServerSideProps或方案2的中间件)。
/checkout/success的额外处理
这个页面是支付完成后的回调页,除了前置导航校验,还要确保用户确实发起过支付请求:
- 发起支付时生成唯一订单ID并存入会话
- 在success页面校验订单ID的有效性,同时检查请求来源是否为支付网关或/checkout页面
内容的提问来源于stack exchange,提问作者Poumon
相关产品推荐
相关产品推荐

