Skip to content

升级2.23.0后出现前端无法访问,但是后端访问正常 #8412

Description

@pandyzhou

前置条件

  • 已经在 issues 列表中搜索了相关问题。
  • 这是 Halo 项目本身存在的问题,如果是非项目本身的问题(如:安装部署问题),建议在 Discussions 提交。
  • 已经尝试过停用所有的插件,排除是插件导致的问题。
  • 如果是插件和主题的问题,请在对应的插件和主题仓库提交。

系统信息

版本:2.23.0

使用的哪种方式运行?

Docker

发生了什么?

通过ai完成了修复,以下是ai给出的结论:

Bug 原因

Halo 2.23.0 升级了 Reactor Core 到 3.8.3,这个版本的 Mono.cacheInvalidateIf() 要求源 Mono 必须产生一个值,如果源完成为空(Mono.empty()),会直接抛出 NoSuchElementException: cacheInvalidateWhen expects a value, source completed empty。

代码中有两处使用了 cacheInvalidateIf,都没有对空源做兜底:

1. DefaultReactiveSettingFetcher(主要触发点)

插件的配置获取器,当插件没有 configMapName 或对应的 ConfigMap 在数据库中不存在时,直接返回 Mono.empty() 给 cacheInvalidateIf,导致异常。前端模板渲染时会调用插件提供的 Thymeleaf finder,触发这个路径。

2. DefaultSystemConfigFetcher(防御性问题)

系统配置获取器,computeSystemConfig() 用 Mono.zip 合并默认配置和覆盖配置。Mono.zip 的特性是任一源为空则整体为空。虽然外层有 defaultIfEmpty(Map.of()),但 getOverrideConfigMap 没有 switchIfEmpty 兜底,在极端竞态条件下可能导致同样的问题。

修复方法

DefaultReactiveSettingFetcher.java:

  • configMapName 为空时,从 return Mono.empty() 改为 return Mono.just(emptyConfigMap())
  • client.fetch() 返回空时,加 .switchIfEmpty(Mono.fromSupplier(DefaultReactiveSettingFetcher::emptyConfigMap)) 兜底

DefaultSystemConfigFetcher.java:

  • 给 getOverrideConfigMap 和 getDefaultConfigMap 都加上 .switchIfEmpty(...) 返回空数据的 ConfigMap,确保 Mono.zip 不会因为任一源为空而整体完成为空

核心思路就是保证传给 cacheInvalidateIf 的源 Mono 永远不会完成为空。

复现步骤

No response

相关日志输出

附加信息

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions