Spring Boot i18n自定义SessionLocaleResolver不生效报错排查
问题根本原因
两个核心问题同时存在,导致配置不生效:
- 自定义LocaleResolver的Bean名称不符合Spring MVC的强制约定
Spring MVC的DispatcherServlet在初始化时,会固定去Spring容器中查找名称为localeResolver、类型为LocaleResolver的Bean作为全局区域解析器。如果找不到这个名称的Bean,框架会自动注册默认的AcceptHeaderLocaleResolver。
你当前配置中Bean的方法名是defaultLocaleResolver,对应容器中Bean的名称就是defaultLocaleResolver,框架识别不到这是你自定义的区域解析器,因此直接加载了默认实现。而AcceptHeaderLocaleResolver本身是只读实现,不允许运行时通过请求参数修改区域设置,这就是抛出Cannot change HTTP accept header - use a different locale resolution strategy错误的直接原因。 - 会话策略和你选择的SessionLocaleResolver完全冲突
你在Spring Security配置中将会话创建策略设置为SessionCreationPolicy.STATELESS,这个策略下框架永远不会创建、也不会使用服务端HttpSession存储任何状态。就算你把Bean名称改对了,SessionLocaleResolver也找不到可用的Session来存储用户选择的语言,根本无法正常工作,和REST接口无状态的设计目标相悖。
补充说明:你的单元测试能正常通过,是因为测试逻辑直接调用MessageSource接口、手动传入Locale参数取值,完全跳过了Web请求链路中LocaleResolver自动解析区域的流程,因此无法检测到Web层的配置错误。
修复方案
推荐选择适配无状态REST架构的方案,不需要修改现有Security的会话策略:
方案一:使用CookieLocaleResolver(推荐,兼顾用户体验和无状态特性)
不需要服务端存储Session,将用户选择的语言存在客户端Cookie中,后续请求无需重复携带lang参数:
- 修改WebMvcConf类中的LocaleResolver Bean,将方法名改为
localeResolver,替换实现类:
@Bean public LocaleResolver localeResolver(){ CookieLocaleResolver resolver = new CookieLocaleResolver(); resolver.setDefaultLocale(idnLocale); // Cookie有效期设置为30天,按需调整即可 resolver.setCookieMaxAge(30 * 24 * 60 * 60); resolver.setCookiePath("/"); return resolver; }
- 你原有的
LocaleChangeInterceptor配置不需要修改,重启应用后,带lang=en参数的请求会正常切换语言,语言设置会保存在客户端Cookie中。
方案二:自定义无状态参数解析器(完全无状态,每次请求需携带lang参数)
如果不想用Cookie,要求每次请求显式携带lang参数指定语言,可以自定义简单的解析器实现,同样将Bean名称设为localeResolver:
@Bean public LocaleResolver localeResolver() { return new AbstractLocaleResolver() { @Override public Locale resolveLocale(HttpServletRequest request) { String langParam = request.getParameter("lang"); if (langParam != null && !langParam.isBlank()) { return Locale.forLanguageTag(langParam); } // 未传lang参数时使用默认印尼语,可按需扩展逻辑读取Accept-Language请求头 return idnLocale; } @Override public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { // 无状态模式不需要持久化存储区域设置,空实现即可 } }; }
不推荐的方案:如果一定要用SessionLocaleResolver
需要修改Spring Security的会话策略,将SessionCreationPolicy.STATELESS改为SessionCreationPolicy.IF_REQUIRED,同时保证LocaleResolver的Bean名称为localeResolver,但这种方案破坏了REST接口的无状态特性,除非有特殊需求否则不建议使用。
内容的提问来源于stack exchange,提问作者rizesky
相关产品推荐
相关产品推荐

