Skip to content

v2.1.1(20261031) ​

适用于 v2.1.0 → v2.1.1。更早版本先完成此前版本迁移。本次没有新增数据库迁移,也没有前端 API、路由或组件调用方式的迁移。

升级前备份数据库、资源文件、实际环境配置和上一版本制品;下面的修改应用于实际加载的 config/{profile}/oss.yml,不要直接覆盖现网连接和凭据。

1. 资源大小:明确单位 ​

把每个 sz.resource.scenes[].max-size 的旧 MB 数值改成带单位写法,例如:

原值改为
33MB
55MB
1010MB

新版本的无单位数字表示字节。全局 sz.resource.security.max-size 原本已使用带单位格式,保留例如 50MB;场景上限为 0 或省略时仍受全局限制。

验证:正常大小的头像、附件可上传,超过生效上限的文件被拒绝。

二开代码若直接调用 ResourceSceneConfig.setMaxSize(10),改为 setMaxSize(DataSize.ofMegabytes(10));读取字节数时先判断 null 再调用 toBytes(),删除原有重复的 MB 换算。类型与校验变更

2. OSS:公共配置复用,场景也能各用一套连接 ​

这次调整让公共参数集中在 sz.oss 中,场景只填写自己的差异。已有单一存储连接可以继续使用;需要连接多个服务时,再为场景增加独立配置。 使用 RustFS、MinIO 或云存储不会自动搬迁历史文件。

多个场景共用一套 OSS ​

在 sz.oss 维护 endpoint、AK/SK 和默认桶,场景设置 type: OSS,省略重复连接参数;省略 bucket 时使用全局 bucketName。只需要换桶或签名区域时,场景单独填写 bucket 或 region 即可。

精简配置前确认原有语义:endpoint 自带协议时无需 scheme 补全,但不带协议的 domain 仍使用 scheme;非默认签名区域必须保留 region。旧 force-path-style 可继续使用,不能与新增 addressing-style 冲突。

每个场景拥有独立的 S3 连接 ​

为目标场景完整填写 endpoint、access-key、secret-key,就可以让它使用不同服务地址和账号。其他场景继续继承全局连接;各场景还可分别指定 provider、bucket、region 和寻址方式。

示例:业务附件复用全局 RustFS,归档附件单独连接另一套 MinIO

以下是配置写法示例,环境变量由部署方提供,合并到现有配置时保留其他场景:

yaml
sz:
  oss:
    provider: RUSTFS
    endpoint: ${OSS_ENDPOINT}
    access-key: ${OSS_ACCESS_KEY}
    secret-key: ${OSS_SECRET_KEY}
    bucket-name: ${OSS_BUCKET}
  resource:
    scenes:
      # 复用全局地址、凭据和默认桶
      - code: business.attachment
        type: OSS
        serve-mode: PROTECTED
        max-size: 10MB

      # 使用另一套地址、凭据和桶
      - code: archive.attachment
        type: OSS
        serve-mode: PROTECTED
        provider: MINIO
        endpoint: ${ARCHIVE_OSS_ENDPOINT}
        access-key: ${ARCHIVE_OSS_ACCESS_KEY}
        secret-key: ${ARCHIVE_OSS_SECRET_KEY}
        bucket: ${ARCHIVE_OSS_BUCKET}
        max-size: 10MB

当前实现仍需一套有效的全局默认连接来启用 OSS,不能只填写场景连接后删掉整个 sz.oss。相同连接规格会复用客户端,修改连接参数后需重启应用。

公开展示的场景显式使用 DIRECT:场景 base-url 优先;默认连接未填写它时依次用全局 domain、endpoint。独立连接不继承全局 domain,需要独立 CDN 时填写自己的 base-url。PRESIGNED 使用各自 endpoint 签名;PROTECTED 继续通过业务接口下载,不配置公开地址。

自定义配置缺少通用富文本场景 system.richtext 时,参照新版配置补齐;LOCAL 场景不能携带 bucket 或 OSS 连接字段。

验证:按场景分别上传、查看或下载,确认文件进入各自目标服务和桶,历史文件仍可访问。使用 DIRECT、PRESIGNED、PROTECTED 的场景分别验证,不能只测默认连接。

3. 本地磁盘存储:生产公开文件交给 Nginx ​

本节的 Nginx 配置适用于将文件保存在服务器本地磁盘或 Docker 挂载目录的项目。使用 S3 OSS 的场景不需要新增本地静态目录;本地受保护附件仍由业务接口读取,不纳入公开目录。

为什么关闭开发入口 ​

GET /resource/file/{sceneDir}/** 是为本地调试保留的便利入口,默认完整路径为 /api/admin/resource/file/{sceneDir}/**。它让开发者在没有 Nginx、没有对象存储时,也能测试 LOCAL 上传并查看磁盘上的文件。

这个入口仅匿名读取 LOCAL DIRECT 公开场景,不承担业务权限校验。生产环境不推荐继续用它分发文件:

  • 安全边界:公开目录需要单独管理,受保护附件必须保留业务鉴权,不能混入匿名静态访问。
  • 服务开销:文件下载会占用 Java 应用的连接和 I/O 资源。公开文件交给独立 Nginx,可避免静态分发与业务请求共用应用资源。

本次升级将开发文件入口改由 sz.resource.dev-file-server.enabled 显式控制。各环境的 oss.yml 应配置为:

配置文件sz.resource.dev-file-server.enabled
config/local/oss.ymltrue:供本地调试
config/dev/oss.ymlfalse
config/preview/oss.ymlfalse
config/prod/oss.ymlfalse

省略该参数时默认 false。入口是否开启取决于这个参数值,不会因为环境名为 prod 而自动关闭;实际部署时应明确核对 sz.resource.dev-file-server.enabled: false。

关闭此入口不影响 LOCAL 上传,也不要求把文件迁到 OSS。

按 sz-deploy-v3 切换到 Nginx ​

sz-deploy-v3 已提供独立 nginx-static 服务,只公开四个 LOCAL DIRECT 目录。普通和蓝绿部署的文件访问路径相同:

text
浏览器 /resource/logo/相对路径
  → 前端 Nginx
  → nginx-static:80
  → /data/logo/相对路径

若已使用部署仓的这些配置,且公开文件能通过 /resource/ 访问,只需核对开关和历史链接;下面三步用于仍依赖 Java 开发入口的部署。合并配置时不要重跑安装或改变普通/蓝绿模式。以下以默认服务名和容器内 /data 为例。

第一步:让后端和静态服务读取同一份文件。

核对两个 Compose 的宿主机资源目录:

服务挂载方式用途
后端 sz-service-admin(蓝绿为两个槽位)RESOURCE_DATA_DIR:/data上传并写入文件
nginx-staticRESOURCE_DATA_DIR:/data:ro只读展示公开文件

RESOURCE_DATA_DIR 默认是 /home/data/sz-resource,存量环境保留实际目录,不能改到一个新空目录。后端的 sz.resource.root 必须对应这份资源;部署仓模板使用 /data。

第二步:对齐公开 URL 和 Nginx 目录。

在实际 config/{profile}/oss.yml 中,仅修改 LOCAL DIRECT 场景的 base-url,保留原 code、path、objectKey 和文件位置:

场景 code场景 path生产 base-url
admin.user.logologo/resource/logo
teacher.richtextteacher-richtext/resource/teacher-richtext
system.richtextrichtext/resource/richtext
system.temptemp/resource/temp

原本使用 OSS 的场景保持 OSS,不套用此表。自定义 LOCAL DIRECT 场景需增加自己的公开目录映射。

部署仓 sz-nginx-static/conf.d/default.conf 中的核心配置如下。以下是现有 server 内的片段,其他公开目录的白名单保留:

nginx
location /resource/logo/ {
    alias /data/logo/;
    autoindex off;
    try_files $uri =404;
}

# 其他公开目录也要逐个列出;未列出的路径不开放。
location /resource/ {
    return 404;
}

前端 Nginx 保留 /resource/ 到 resource_backend(nginx-static:80)的代理,proxy_pass http://resource_backend; 不追加 URI,完整传递 /resource/...。若现场缺少该代理,合并对应模板中的 upstream resource_backend 和 location /resource/,保留原 API、WebSocket 路由。普通与蓝绿各使用对应的前端配置,不能同时加载两份;蓝绿内部的 sz-service-nginx 无需新增静态映射。

template.excel、teacher.attachment、system.protected 等受保护文件继续走业务接口。不要公开整个 /data,也不要在公开目录放置指向受保护目录的符号链接;只读挂载限制写入,不提供访问授权。

第三步:先验证 Nginx,再关闭 Java 开发入口。

已有服务且挂载未变化时,更新运行目录中的配置,先检查再加载:

bash
docker exec nginx-static nginx -t
docker exec sz-admin nginx -t
docker exec nginx-static nginx -s reload
docker exec sz-admin nginx -s reload

容器名自定义时替换为实际名称。若新增静态服务或修改了挂载,先在对应服务运行目录执行以下命令,再检查 Nginx;reload 不会应用新挂载。默认目录分别为 /home/docker-compose/sz-nginx-static 和 /home/docker-compose/sz-admin,保留各目录已有 .env:

bash
docker compose --env-file .env -f docker-compose.yml config -q
docker compose --env-file .env -f docker-compose.yml up -d

确认 Nginx 能读取已有公开文件后,在实际资源配置中合并以下开关,并按现有发布流程重启/更新后端:

yaml
sz:
  resource:
    dev-file-server:
      enabled: false

历史富文本可能直接保存旧 /api/admin/resource/file/... 图片地址,修改 base-url 不会自动改写它们。关闭开发入口前,检查已有文章;仍使用旧地址时,在前端 Nginx 为上述公开目录保留受限兼容映射,或完成内容地址迁移。

兼容建议:将四个公开目录的旧链接转到 Nginx 新地址

仅在确认存在同源旧链接时,将以下片段加入前端 Nginx 的现有 server 块,并重新检查、加载配置。这是可选兼容配置,部署仓默认未包含;自定义 API 前缀时修改匹配前缀:

nginx
location ~ ^/api/admin/resource/file/(logo|teacher-richtext|richtext|temp)/(.*)$ {
    return 302 /resource/$1/$2$is_args$args;
}

逐一打开旧链接,确认跳转后仍是对应公开文件。若旧地址指向旧域名或浏览器本机的 127.0.0.1,还需修正原内容地址,不能只依靠当前站点的路径映射。

不要为兼容旧图片继续开启 Java 开发入口,也不要开放整个旧文件前缀。

验证:旧文件和新上传图片都能经同源 /resource/... 查看;不存在的文件及非白名单目录不返回文件或目录列表;受保护附件仍需业务权限。直接访问后端开发路由不再返回文件。不要仅用未登录的 401 判断路由已关闭。

对应源码:共享目录挂载、静态目录白名单、普通前端代理、蓝绿前端代理。

4. 前端:升级 Node.js 24.22.1 ​

开发机和自建 CI 使用 Node.js 24.22.1、pnpm 10.17.1。同步 .nvmrc、package.json、pnpm-lock.yaml、tsconfig.node.json,在前端工程执行:

bash
node --version
pnpm --version
pnpm install --frozen-lockfile
pnpm run type-check
pnpm run build

验证:版本分别显示 v24.22.1、10.17.1,安装、类型检查和构建成功,再发布新 dist 或前端镜像。线上 Nginx 容器不需要安装 Node.js。

本次选择 24.22.1 是为了纳入 2026-10-21 的 Node.js 安全修复,并替换已结束维护的 Node.js 20;详细原因见更新日志。

5. Java:更新证书信任库 ​

Java 仍使用 25,但需要更新实际运行时的信任库:

  • 使用镜像:部署包含本次加固的新镜像,核对源码 revision 和镜像摘要后重建容器。对待部署镜像执行 /usr/local/bin/harden-java-truststore --check,应提示禁止 alias 数量为 0。
  • 自建镜像:同步 Dockerfile、公共构建脚本、Truststore 脚本和拒绝策略文件;沿用公共脚本准备的 target/.java-security 构建上下文。只复制新 Dockerfile 会缺少安全文件。完整变更
  • 裸 JAR、自定义 JDK 或外置 truststore:先备份实际信任库,再按 Oracle 处置说明或项目加固脚本移除对应根证书并复查,随后重启 Java 进程。官方镜像中的处理不会自动作用于这些环境。

验证:更新实例通过信任库检查,OSS、微信等实际 HTTPS 连接成功。检查覆盖的是本次根证书拒绝策略,不代表所有 JDK 漏洞清零;TLS 失败时修正上游证书链,不关闭证书验证。

6. 发布验证与回滚 ​

发布后检查:登录正常;头像和富文本图片可查看;有权限的用户可下载业务附件,无权限用户不能取得内容;旧文件仍可读取,正常文件路径不跨场景或资源根目录。数据库沿用原配置和 Liquibase 历史,不执行新的初始化脚本。

回滚时同时恢复匹配的后端与配置:旧版本不能读取场景 3MB 字符串,不能只回退 JAR 而保留新配置。 保留证书安全加固,并核对升级后新增文件的路径和引用。若另外切换过存储服务,恢复配置不会把文件迁回。

返回升级索引