
基于地理位置的国家级访问拦截使用 Edge Middleware 与 vercel/functions 实现 Geolocation Country Block【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples导读本文围绕仓库中 edge-middleware/geolocation-country-block 示例讲解如何在 Next.js 的 Edge Middleware 中利用vercel/functions提供的geolocation()API 获取访客所在国家并针对特定国家如奥地利实施访问拦截返回 HTTP 451 状态码或重写到自定义拦截页。读完本文你将掌握边缘节点地理位置识别、NextResponse.rewrite重写流程、动态路由页面配套渲染以及从本地开发到云端部署的完整实战方案。一、核心思路把地理位置判断放在边缘传统的按国家拦截通常依赖后端服务端逻辑或 CDN 规则。本示例的差异化做法是将国家判断放在 Edge Middleware 中执行。Edge Middleware 运行在 Vercel 边缘网络节点上靠近用户因此具备两大优势低延迟请求到达离用户最近的边缘节点时即可完成判断无需回源到服务器轻量高效middleware 只做路径重写与响应控制不涉及重量级计算适合做访问控制、A/B 分流、区域化内容分发等场景。原文档给出了一个最小化的直接响应版本判断到目标国家后直接返回一个 451 响应。而仓库中的真实实现更进一步通过NextResponse.rewrite将请求内部重写到对应的页面路由由 Next.js 页面完成渲染。两者是同一思想下的两种落地形态下文会分别展开。二、最小化实现直接返回 451 响应原文档的核心代码极其精简适合快速理解机制import { geolocation } from vercel/functions import type { NextRequest } from next/server // Block Austria, prefer Germany const BLOCKED_COUNTRY AT export default function middleware(req: NextRequest) { const country geolocation(req).country || US if (country BLOCKED_COUNTRY) { return new Response(Blocked for legal reasons, { status: 451 }) } return new Response(Greetings from ${country}, where you are not blocked.) }这段代码的关键点geolocation(req)来自vercel/functions包读取请求对象并返回地理位置信息。这里的req就是 middleware 接收到的NextRequest。country || US当无法解析到国家时回退到US保证逻辑始终有一个默认分支。HTTP 451451 Unavailable For Legal Reasons是专为因法律原因不可用设计的 HTTP 状态码语义上比单纯的 403/404 更贴切——这正是该示例在代码注释中写 Blocked for legal reasons 的原因。被拦截的访客会收到纯文本Blocked for legal reasons其他国家的访客则收到Greetings from {country}, where you are not blocked.。三、仓库完整实现重写到页面路由如果直接返回纯文本响应页面体验和可扩展性都有限。仓库中的 middleware.ts 给出了更完整的工程化写法——用NextResponse.rewrite把请求重写到对应的 Next.js 页面import { geolocation } from vercel/functions import type { NextRequest } from next/server import { NextResponse } from next/server // Block Austria, prefer Germany const BLOCKED_COUNTRY AT // Limit middleware pathname config export const config { matcher: /, } export default function middleware(req: NextRequest) { const geo geolocation(req) // Extract country const country geo.country || US // Specify the correct pathname if (country BLOCKED_COUNTRY) { req.nextUrl.pathname /blocked } else { req.nextUrl.pathname /${country} } // Rewrite to URL return NextResponse.rewrite(req.nextUrl) }与最小化版本的差异及进阶点config.matcher: /middleware 默认会拦截所有匹配的请求。这里通过matcher限定只在访问首页/时触发避免对全站静态资源CSS、JS、图片等做无谓的地理位置计算。生产环境中应根据需要扩大或缩小匹配范围。req.nextUrl.pathname重写middleware 不直接渲染内容而是修改req.nextUrl的pathname后再用NextResponse.rewrite返回。浏览器地址栏 URL 保持不变但对用户来说服务端实际渲染的是重写后的页面。来自奥地利AT的访客 → 重写到/blocked其他国家 → 重写到/{country}如/DE、/US、/JP。geo.country || US的兜底与文档版本一致无法识别国家时按US处理走允许访问分支避免误伤。从源码结构看这种middleware 决策 页面渲染的分层设计把谁可以访问和展示什么内容彻底解耦middleware 只负责路由决策页面只负责展示后续要扩展拦截逻辑如按 IP、按请求头时无需改动页面代码。四、配套页面拦截页与动态国家页重写目标需要对应的页面承接仓库在pages目录下提供了两个路由文件4.1 拦截页 blocked.tsx被拦截的访客最终看到的就是这个极简页面const BlockedPage: React.FC () { return pBlocked for legal reasons/p } export default BlockedPage在实际项目中这里可以扩展为完整的法律声明页面、申诉入口或企业联系信息。4.2 动态国家页 pages/[country].tsx允许访问的国家走的是动态路由/[country]页面接收路径参数country并渲染问候语import { GetStaticProps } from next import { ParsedUrlQuery } from querystring interface Props { country: string } interface Params extends ParsedUrlQuery { country: string } export const getStaticPaths async () { return { paths: [], fallback: blocking, } } export const getStaticProps: GetStaticPropsProps, Params async ({ params: { country }, }) { return { props: { country, }, } } const AllowedPage ({ country }: Props) { return p{Greetings from ${country}, where you are not blocked.}/p } export default AllowedPage这里的实现细节值得注意getStaticPaths返回空pathsfallback: blocking由于国家集合无法在构建时穷举采用按需静态生成ISR/SSG 的 blocking fallback 模式。首次访问某国家路径时才在服务端生成该页面之后可被缓存兼顾了静态化的性能与国家的动态性。getStaticProps从params中取country页面拿到的是 middleware 重写后的路径参数因此/{country}中的国家代码与geolocation()返回的 ISO 3166-1 alpha-2 国家代码一一对应。至此完整请求链路为访客请求 / → Edge Middleware 读取 geolocation(req).country ├─ AT → rewrite 到 /blocked → 渲染 Blocked for legal reasons └─ 其他 → rewrite 到 /{country} → 按需静态生成并渲染 Greetings from {country}...五、geolocation() 返回的地理信息字段geolocation()的返回对象不止country一个字段。仓库中同目录的姊妹示例 edge-middleware/geolocation/README.md 完整列出了所有可用字段{ /** The city that the request originated from. */ city?: string; /** The country that the request originated from. */ country?: string; /** The flag emoji for the country the request originated from. */ flag?: string; /** The Vercel Edge Network region that received the request. */ region?: string; /** The region part of the ISO 3166-2 code of the client IP. */ countryRegion?: string; /** The latitude of the client. */ latitude?: string; /** The longitude of the client. */ longitude?: string; }字段说明与应用建议字段含义典型用途country请求来源国家ISO 3166-1 alpha-2 代码国家拦截、区域定价、语言路由city请求来源城市本地化内容、附近门店展示countryRegion客户 IP 对应的 ISO 3166-2 省级/州级区域码州级合规限制、州级税率flag国家旗帜 emojiUI 上的国旗展示region接收请求的 Vercel 边缘网络区域运营监控、就近统计latitude/longitude客户端经纬度距离计算、地图定位该姊妹示例还演示了基于这些字段做更丰富的场景读取国家信息后解析出该国货币代码、货币符号与语言列表写入url.searchParams后重写到页面实现按国家展示货币和语言的本地化体验见 geolocation middleware。这说明geolocation()是一个通用的边缘地理位置基础设施国家拦截只是其能力之一。六、环境与依赖仓库的 package.json 揭示了运行本示例所需的依赖版本dependencies: { vercel/functions: ^1.5.0, next: ^16.0.10, react: ^19.2.1, react-dom: ^19.2.1 }要点vercel/functions是本示例的核心依赖geolocation()由它导出。middleware 运行在边缘运行时因此该函数无需访问 Node.js 原生模块也不会引入额外网络请求项目基于Next.js 16Pages Router与React 19类型配置参见 tsconfig.jsonstrict: false、moduleResolution: node等部署构建命令由 vercel.json 指定为pnpm turbo build并通过turbo-ignore实现仅在有变更时触发构建。需要强调的是geolocation()的地理位置数据由Vercel 边缘网络在请求进入时注入。因此在本地pnpm dev环境中该 API 返回的地理信息通常依赖 Vercel 开发代理注入其行为与线上环境一致性的验证以部署后的线上表现为准。七、运行与部署原文档提供了两种使用方式此处完整保留并补充说明方式一一键部署到 Vercel原文档提供 Vercel 的一键部署入口点击后即可基于本示例仓库创建项目并直接部署无需本地环境。部署完成后即可用不同地区的网络访问验证拦截效果。注意该示例按国家拦截geolocation()数据在本地开发与线上略有差异线上验证最准确。方式二克隆到本地并部署使用create-next-app配合 pnpm从本示例脚手架化一个全新项目pnpm create next-app --example https://github.com/vercel/examples/tree/main/edge-middleware/geolocation-country-block geolocation-country-block该命令会拉取本示例的完整代码middleware、pages、配置文件等到geolocation-country-block目录并安装依赖。随后进入开发模式pnpm dev在开发模式下middleware 会随 Next.js 开发服务器一起运行可以本地调试重写逻辑与页面渲染。完成开发后构建并部署pnpm build # 或 pnpm turbo build与 vercel.json 中的构建命令一致 pnpm start最后将项目部署到 Vercel 云平台即可在全球边缘节点上生效。部署后可使用代理或切换网络环境模拟奥地利AT与德国DE等国家的访客验证AT 被拦截、其他国家正常展示问候语的预期行为。八、扩展方向与注意事项围绕本示例的机制可以自然延伸出以下实战能力多国拦截清单将BLOCKED_COUNTRY从单个字符串扩展为数组或配置文件例如const BLOCKED [AT, CU, IR]用BLOCKED.includes(country)判断适用于合规受限的多地区场景结合其他地理字段利用countryRegion做州级限制或结合flag、city做更细粒度的本地化展示拦截策略与页面解耦middleware 只负责rewrite拦截页与业务页各自独立演进便于团队分工matcher 范围控制合理设置config.matcher避免 middleware 对静态资源与 API 产生不必要的开销。注意事项middleware 中不宜放置重量级计算或过大的依赖geolocation()依赖 Vercel 平台注入若部署在其他运行时如自托管 Next.js地理位置来源需另行接入HTTP 451 仅适合法律原因语义的场景若是普通的地域限制如内容授权分区可考虑 403 或其他状态码。小结本示例用不到三十行核心代码演示了边缘地理位置识别 → 按国家决策 → 重写路由 → 页面渲染的完整闭环。无论是最小化的 451 直接响应还是仓库中 rewrite 到动态页面的工程化版本其核心都建立在vercel/functions的geolocation()之上。理解这一模式后你可以将同样的思路迁移到区域定价、语言路由、合规拦截等更多边缘场景。【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考