记一次 Halo 后台界面突然变成英文:一场浏览器缓存引发的假故障
前言:后台突然「说英文」了
2026-10-16 凌晨,我照常打开 Halo 后台准备做点日常维护,在转换插件联系表单中的旧模板后愣住了:左侧菜单、按钮、各种提示文案全都变成了英文。我靠,前一秒还是好好的,这时我突然想起来 Halo 社区 中的一篇帖子:安装插件朋友圈之后 全部变成英文 。
当时的第一反应是语言设置被改掉了,于是进设置里把语言从简体中文切到英文,再切回简体中文。结果发现一个很有意思的现象:其他语言都显示正常,唯独简体中文这一份是英文——也就是说简体中文的语言包没有生效,界面回退到了默认语言。
既然只有某一份语言资源异常,那问题就不在「整个后台崩了」,而是某个资源文件加载失败。顺着这个方向查下去,很快就在日志里找到了答案。
排查过程:五步定位到浏览器缓存
整个过程我按顺序记录了下来,前面四步都在做「排除」,最后一步才真正解决问题:
服务端日志:一份 i18n 资源返回了 500
第二步提到的报错,是这次排查最关键的一条线索。在后台日志里找到了这样一条记录(时间戳刚好和我发现问题的时间对得上):
2026-10-16T02:04:09.148+08:00 ERROR 1 --- [loomBoundedElastic-87912] b.w.a.e.AbstractErrorWebExceptionHandler : [c14bcc85-12902] 500 Server Error for HTTP GET "/ui-assets/virtual_intlify-i18n-2-PT1tSPn9.js"
java.util.zip.ZipException: invalid stored block lengths
at java.base/java.util.zip.InflaterInputStream.read(Unknown Source) ~[na:na]
Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
Error has been observed at the following site(s):
*__checkpoint ⇢ run.halo.app.security.InitializeRedirectionWebFilter@2b058bfd
*__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy@1d1fd2aa
*__checkpoint ⇢ run.halo.seo.tools.redirect.AdvancedRedirectWebFilter@66c3825
*__checkpoint ⇢ run.halo.moments.rss.OldRssRouteRedirectionFilter@4c644176
*__checkpoint ⇢ com.timxs.bbs.comment.BbsLockedCommentFilter@51017b62
*__checkpoint ⇢ com.xhhao.insight.metrics.RequestObservationFilter@71f090c
*__checkpoint ⇢ top.ilay.authpasskey.PasskeyLoginContextWebFilter@46e76e1d
*__checkpoint ⇢ run.halo.seo.tools.traffic.SearchTrafficFilter@2f76bdc1
*__checkpoint ⇢ run.halo.seo.tools.crawl.CrawlRecordFilter@2166fda3
*__checkpoint ⇢ cc.ryanc.staticpages.endpoint.RewriteOnNotFoundFilter@57062700
*__checkpoint ⇢ run.halo.router.TrailingSlashRedirectFilter@112cbca7
*__checkpoint ⇢ run.halo.app.infra.webfilter.AdditionalWebFilterChainProxy@178c6261
*__checkpoint ⇢ org.springframework.web.filter.reactive.ServerWebExchangeContextFilter@78e50fca
*__checkpoint ⇢ run.halo.app.infra.webfilter.LocaleChangeWebFilter@128a188a
*__checkpoint ⇢ org.springframework.web.filter.reactive.UrlHandlerFilter@5cfe28e1
*__checkpoint ⇢ run.halo.app.theme.UserLocaleRequestAttributeWriteFilter@2bf4fa1
*__checkpoint ⇢ HTTP GET "/ui-assets/virtual_intlify-i18n-2-PT1tSPn9.js" [ExceptionHandlingWebHandler]
Original Stack Trace:
at java.base/java.util.zip.InflaterInputStream.read(Unknown Source) ~[na:na]
at java.base/java.io.FilterInputStream.read(Unknown Source) ~[na:na]
at java.base/java.nio.channels.Channels$ReadableByteChannelImpl.read(Unknown Source) ~[na:na]
at org.springframework.core.io.buffer.DataBufferUtils$ReadableByteChannelGenerator.accept(DataBufferUtils.java:994) ~[spring-core-7.0.9.jar:7.0.9]
at org.springframework.core.io.buffer.DataBufferUtils$ReadableByteChannelGenerator.accept(DataBufferUtils.java:970) ~[spring-core-7.0.9.jar:7.0.9]
at reactor.core.publisher.FluxGenerate.lambda$new$0(FluxGenerate.java:58) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxGenerate$GenerateSubscription.slowPath(FluxGenerate.java:270) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxGenerate$GenerateSubscription.request(FluxGenerate.java:212) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxUsing$UsingFuseableSubscriber.request(FluxUsing.java:319) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2325) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:338) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:138) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.requestUpstream(FluxSubscribeOn.java:134) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.onSubscribe(FluxSubscribeOn.java:127) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:103) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:163) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxLimitRequest$FluxLimitRequestSubscriber.onSubscribe(FluxLimitRequest.java:132) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:69) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:67) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:197) ~[reactor-core-3.8.7.jar:3.8.7]
at reactor.core.scheduler.BoundedElasticThreadPerTaskScheduler$SchedulerTask.run(BoundedElasticThreadPerTaskScheduler.java:1016) ~[reactor-core-3.8.7.jar:3.8.7]
at java.base/java.lang.VirtualThread.run(Unknown Source) ~[na:na]这条日志的信息量其实很明确:浏览器在请求 /ui-assets/ 下那份名为 virtual_intlify-i18n-2-PT1tSPn9.js 的界面资源时,服务端返回了 500;而异常发生在解压读取(Inflate)的环节,说明服务端拿到的这份资源的压缩数据是损坏或不完整的,解压直接失败。
为什么界面会「退回英文」
Halo 后台的界面文案是由一份 i18n 资源包提供的,文件名里的 virtual_intlify-i18n-2-*.js 就是它的构建产物。这份 JS 加载失败时,前端并不会白屏或弹报错窗口,而是回退到默认语言(英文),于是看上去就像「语言设置丢了」——这也是我一开始走弯路、跑去反复切换语言的原因。
结合上面的排查过程,整件事基本可以还原成这样:某次请求中,这份资源被写入了一份损坏的内容,浏览器把这坏掉的一份存进了本地缓存;之后每次打开后台都直接复用这份缓存,简体中文就一直「变成英文」。换浏览器和隐私模式命中不到这份缓存,所以一切正常;而
几条顺手记下的经验
2. 不要急着清空全部网站数据:先试一次强制刷新,避免把登录态、主题偏好等一起清掉。
3. 顺手看一眼日志:像这次的
ZipException: invalid stored block lengths,能直接告诉你坏掉的是哪个静态资源。4. 如果强制刷新也无效:那就要怀疑服务端那份资源真的损坏了,可以尝试重启 Halo、重新部署 Halo,再不行就到社区反馈。
这次故障本身并不严重,但排查路径挺典型:先用「切换语言」缩小范围,再用「换浏览器 / 隐私模式」区分服务端与本地,最后一步强刷收尾。下次遇到「某个界面元素突然不对,但换台设备就好了」的情况,不妨先想想是不是又被缓存摆了一道。