Next.js使用@formatjs/intl-localematcher遇RangeError报错求助
排查Next.js + @formatjs/intl-localematcher在Vercel预览环境的RangeError问题
以下是几个大概率导致该报错的原因及对应排查方案:
1. 请求头Accept-Language包含非法locale格式
Vercel预览环境的请求头可能携带不符合BCP 47规范的locale值(比如带异常后缀、拼写错误,甚至空值),matchLocale对非法输入容错性极低,即便配置了默认值,也可能因为候选列表完全无法解析而报错。
解决方法:在中间件中先过滤并格式化请求头的locale值,确保传入matchLocale的都是合法候选值:
import { matchLocale } from '@formatjs/intl-localematcher'; import Negotiator from 'negotiator'; const supportedLocales = ['en', 'zh-CN', 'ja']; const defaultLocale = 'en'; // 过滤出符合支持列表的合法locale function filterValidLocales(acceptLanguage: string | undefined) { if (!acceptLanguage) return []; return acceptLanguage.split(',') .map(lang => lang.split(';')[0].trim()) .filter(lang => supportedLocales.includes(lang)); } export function middleware(request: NextRequest) { const negotiator = new Negotiator({ headers: { 'accept-language': request.headers.get('accept-language') || '' } }); const clientLocales = filterValidLocales(negotiator.language()); // 兜底:确保候选列表至少有一个合法值 const finalLocales = clientLocales.length > 0 ? clientLocales : [defaultLocale]; const matchedLocale = matchLocale(finalLocales, supportedLocales, defaultLocale); // 后续路由匹配逻辑... }
2. Vercel与本地Node.js版本不一致
@formatjs/intl-localematcher依赖Node.js的Intl API,不同版本的Node.js对locale解析的实现存在差异,旧版本可能存在部分locale解析的bug,导致在本地正常的代码到Vercel环境报错。
解决方法:
- 在项目根目录的
package.json中指定Node.js版本:{ "engines": { "node": ">=18.17.0" } } - 登录Vercel控制台,进入项目设置的「General」→「Node.js Version」,手动选择与本地一致的版本。
3. 配置文件中的locale值不符合规范
i18n.config.ts中的locales数组可能包含不符合BCP 47标准的值(比如写cn而非zh-CN),本地环境可能有额外的locale支持,但Vercel环境的Node.js未预装对应locale包,导致解析失败。
解决方法:
- 核对所有locale值,确保符合BCP 47规范(如
en-US、zh-CN); - 用
Intl.getCanonicalLocales()校验并规范化locale:const rawLocales = ['en', 'zh-CN', 'ja']; const validLocales = rawLocales.map(locale => Intl.getCanonicalLocales(locale)[0]);
4. 未处理请求头为空的极端场景
当请求未携带Accept-Language头时,negotiator.language()可能返回空数组或undefined,此时直接传入matchLocale会触发报错。
解决方法:调用matchLocale前强制兜底默认locale,确保候选列表非空:
const clientLocales = negotiator.language() || []; const safeLocales = Array.isArray(clientLocales) ? clientLocales : [clientLocales]; const finalLocales = safeLocales.length > 0 ? safeLocales : [defaultLocale]; const matchedLocale = matchLocale(finalLocales, supportedLocales, defaultLocale);
内容的提问来源于stack exchange,提问作者Lenny
相关产品推荐
相关产品推荐

