HZERO PaaS平台-Docker版demo笔记(二)Docker版测试 问题5-9
问题五、知识问答涉及的跨域访问问题,HKMS服务访问问题和大模型APIkey问题。
测试知识问答,浏览器控制台看到的错误信息是:
Access to XMLHttpRequest at ‘http://aigc.hzero.com.cn/v1/open/image-emb/common’ from origin ‘http://dev.hzero.com.cn’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
分析:这是跨域访问被阻止了,按照元宝建议,nginx反向代理添加内容:
# 添加CORS响应头
add_header ‘Access-Control-Allow-Origin’ ‘http://dev.hzero.com.cn’ always;
add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, OPTIONS, PUT, DELETE’ always;
add_header ‘Access-Control-Allow-Headers’ ‘DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization’ always;
add_header ‘Access-Control-Expose-Headers’ ‘Content-Length,Content-Range’ always;
add_header ‘Access-Control-Allow-Credentials’ ‘true’ always;
重启动nginx
知识库问答执行错误:
控制台错误显示交叉验证策略阻止了访问。
分析:
Aigc.hzero.com.cn是个反向代理地址,浏览器发现有跨域访问,会给目标跨域地址发个预检请求(options类型), 反向代理默认会把所有请求发给被代理的服务,也就是后端的hzero-aip-app:8088, hzero-aip-app会怎么处理呢?看hzero-aip-app的application.yml,其中关于跨域访问的配置是:
# 跨域配置
cors:
allowed-origins:
– ${HZERO_AIP_CORS_ALLOWED_ORIGINS:*}
allowed-headers:
– ${HZERO_AIP_CORS_ALLOWED_HEADERS:*}
allowed-methods:
– ${HZERO_AIP_CORS_ALLOWED_METHODS:*}
也就是说允许任何来源任何方法(按理应该包含options预检方法),所以正常应该是可以的。然后有重新翻了下开放平台上AIGC的部署文档,发现在反向代理的配置的地方跟原来的版本有变化,按照新的变化,更新了nginx反向代理的配置:
server {
listen 80;
server_name aigc.hzero.com.cn;
location / {
proxy_pass http://hzero-aip-app:8088;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
}
}
重启nginx,再测试:
这次没有报跨域访问的错误,只是说链接KMS出了问题,不过这并不稳定,全部容器重启后再次访问,还是出现跨域访问被block的问题,提示很明确:No ‘Access-Control-Allow-Origin’ header is present on the requested resource. 看了哪些网络请求,确实也没提供 Access-Control-Allow-Origin
解决方案:还是在nginx中配置aigc.hzero.com.cn反向代理的地方修改,按照豆包建议做各种nginx的配置修改都没用,最后还是恢复文档中简单配置就又好用了。而且在正常好用的情况下,也没在请求标头中看到Access-Control-Allow-Origin,单独打开没有缓存的chrome测试也是好的。那看来所谓的不稳定表现是原来Edge浏览器缓存原因? nginx配置上不复杂,就按文档就行?后面在多测测吧。
连接KMS的问题:
链接KMS出了什么问题呢?我们查hzero-aip-app服务的日志:
2025-11-29T22:33:19.068+08:00 ERROR 1 — [hzero-aip-app] [r-http-epoll-16] o.h.a.k.domain.search.SearcherWithFlux : HKMS 调用异常:
org.springframework.web.reactive.function.client.WebClientRequestException: finishConnect(..) failed: Connection refused: hzero-hkms/172.18.0.27:18080
从日志看,hzero-aip-app链接HKMS时,链接被拒绝了。那我们先测试这两个容器之间的连通性:
Hzero-aip-app 容器测试访问hzero-hkms:
# echo ‘public class Test { public static void main(String[] args) { try (java.net.Socket s = new java.net.Socket()) { s.connect(new java.net.InetSocketAddress(“hzero-hkms”, 18080), 3000); System.out.println(“✅ 连通成功!”); } catch (Exception e) { System.out.println(“❌ 连通失败: ” + e.getMessage()); } } }’ > Test.java && javac Test.java && java Test && rm -f Test.java Test.class
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 -Duser.language=zh -Duser.region=zh_CN -Duser.country=zh_CN
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 -Duser.language=zh -Duser.region=zh_CN -Duser.country=zh_CN
❌ 连通失败: Connection refused
测试下来就是联通失败,看hzero-hkms容器的ip地址,确实是172.18.0.27,而在hzero-aip-app的application.yml中关于HKMS服务的配置是:
llama:
gateway-path: ${HZERO_KNOWLEDGE_LLAMA_GATEWAY_PATH:http://hzero-hkms:18080}
这么说,aip-aip-app服务,根据配置中的hzero-hkms这个容器服务名正确的解析了其IP地址。也就是网络可达,但链接被拒绝了。猜测是 HKMS的服务访问策略里面做了什么设置,拒绝了某些来源的链接。通常这种设置在哪里呢?我们在浏览器直接访问hkms服务 http://locaohost:18080 是有响应的。
那么拒绝访问的设置是在hkms服务的web配置中?
我先在容器外,linux 主机中测试下链接HKMS服务,是否能成功:
# echo ‘public class Test { public static void main(String[] args) { try (java.net.Socket s = new java.net.Socket()) { s.connect(new java.net.InetSocketAddress(“localhost”, 18080), 3000); System.out.println(“✅ 连通成功!”); } catch (Exception e) { System.out.println(“❌ 连通失败: ” + e.getMessage()); } } }’ > Test.java && javac Test.java && java Test && rm -f Test.java Test.class
✅ 连通成功!
突然发现自己好傻,18080端口是映射到容器外的端口,在容器里面当然访问不了。
解决方案:
更改 hzero-aip-app的application.yml 更改hkms服务的端口,从 18080 改成80
llama:
gateway-path: ${HZERO_KNOWLEDGE_LLAMA_GATEWAY_PATH:http://hzero-hkms:80}
对hzero-hype服务调用的配置端口也要改成80;
同样的问题在hzero-aip-server中也存在,hzero-hkms服务的端口要改成80.
修改完成后,重新构建jar, docker镜像,重启动hzero-aip-app服务 和hzero-aip-server服务。
再次测试知识库问答:
这次没有之前连不上HKMS的错误了,提示了一个新的错误,好型跟大模型调用有关:
查hzero-aip-app服务日志
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for “https://ark.cn-beijing.volces.com/api/v3/chat/completions”: ark.cn-beijing.volces.com
是调用大模型API遇到了IO意外,没有更详细的信息,不过类似的问题在文档向量化处理时提供了更详细的信息,其实就是无法解析大模型API中的域名:
难道是我们把hzero-aip-app放到容器内去运行了,容器内只能解析docker网络内的容器服务名,确实无法解析大模型API的域名?
在模型账号对接的测试的地方也是遇到同样的问题了:出现了DNS 错误。
想着问下豆包如何解决容器内服务访问外网问题,但是豆包断网了。嗯,想起来了,已经是凌晨12点了,家里的wifi设置了自动断网,
临时链接下手机热点,继续问豆包,但是,突然想起这可能是我断网导致的吧,于是再测试模型账号对接测试:发现正常了。确实是断网的原因。
再做文档向量同步也成功了:
知识问答,报了另外一个错误,说是API KEY 错误,大概是重排模型的APIkey 还没填进去
输入正确的api Key之后再测,知识库问答就OK了:
所以核心问题是容器服务hzero-hkms 的端口问题,我们正常再hzero-aip-app服务和hzero-aip-server服务的application.yml中配置的是容器映射到外面的端口,但是在docker compose 网络内部,不能用映射到外面的端口18080,必须是容器内的端口80。
不过,仔细一想,我们在hzero-aip-app和hzero-aip-server的yml配置文件中对hkms访问的端口改成容器的端口也不行,因为我们还要兼容hzero-aip-app和hzero-aip-server两个服务本身没有在docker 容器内运行的情况。所以最合理的做法是保持hzero-aip-app和hzero-aip-server 的yml配置中的18080端口,但是把HKMS的nginx 的web服务端口从80改成18080,这样hkms容器内外端口就保持一致,可以兼容hzero-aip-app和hzero-aip-server服务在docker compose网络内访问和网络外访问的情况。
执行:
Hzero-aip-app 和hzero-aip-server 对hkms的访问端口配置还是恢复到18080, 更改hkms容器Nginx的web服务端口为18080; 更改hkms 容器的docker-compose.yml中的端口映射为18080:18080;
hype服务也要类似做更改,hype容器之前配置的时候,没有把容器内的web服务配置文件挂载出来,所以在hype的docker-compose.yml中要做下挂载
先在volumes中新建hype目录
$ cd /d01/hzero-dockers/volumes
$ mkdir hype
$ sudo chown -R 33:33 ../volumes/hype
$ sudo chmod -R 755 ../volumes/hype
启动hype 容器
$ cd /d01/hzero-dockers/hzero-hype-docker
$ docker compose up -d
#把原来的web服务启动文件拷贝出来
$ docker cp hzero-hype:/root/execute/bin/start.sh /d01/hzero-dockers/volumes/hype/
#关闭容器
更改 /d01/hzero-dockers/volumes/hype/start.sh, 把端口从80改成10080
#docker-compose.yml中挂载
volumes:
– ${DOCKER_VOLUME_DIRECTORY:-../volumes}/hype/start.sh:/root/execute/bin/start.sh
#再启动容器,OK了:
不过有个问题始终存在,那就是每次容器服务全部重启之后再去测试《我的HZERO运营知识库》知识库问答的时候,当我们开始输入问题的时候,系统就会去找相似问题提供选择,这时就会调用aigc.hzero.com.cn 网关中的API了,这个时候涉及跨域,因为我们的原始域是dev.hzero.com.cn , 浏览器发送请求给aigc.hzero.com.cn的时候会告诉服务端这是跨域,等服务端返回消息,要看返回消息中是否包含 响应头(服务器配置):Access-Control-Allow-Origin,并且Access-Control-Allow-Origin 明确是包含了发送的原始域,或者*(所有域);如果返回的消息中没包含,那么浏览器就拒绝把响应消息返回给浏览器前端用户,直接阻塞掉了。
目前测试中发现,当nginx 和 hzero-aip-app 都放在docker容器中运行的时候,nginx的配置中反向代理的域名aigc.hzero.com.cn 指向容器服务名hzero-aip-app:8088 的时候,服务返回的响应中没有Access-Control-Allow-Origin,从而导致被浏览器的Cors(跨域资源共享)策略阻塞。这个时候,如果我们在nginx.conf中配置加上 Access-Control-Allow-Origin: ‘dev.hzero.com.cn’ 也会促发错误,错误信息是Access-Control-Allow-Origin只允许有一条,但实际有两条Access-Control-Allow-Origin: ‘dev.hzero.com.cn’ 和 Access-Control-Allow-Origin: ‘*’ , 我们在hzero-aip-app的服务yml配置中明确是:
# 跨域配置
cors:
allowed-origins:
– ${HZERO_AIP_CORS_ALLOWED_ORIGINS:*}
allowed-headers:
– ${HZERO_AIP_CORS_ALLOWED_HEADERS:*}
allowed-methods:
– ${HZERO_AIP_CORS_ALLOWED_METHODS:*}
所以,正常hzero-aip-app服务返回的响应中肯定是包含Access-Control-Allow-Origin: ‘*’ 的,加上nginx中配置增加的Access-Control-Allow-Origin: ‘dev.hzero.com.cn’就会出现浏览器提示的错误。 不过诡异的是: 既然浏览器能获得后端服务返回的Access-Control-Allow-Origin: ‘*’ ,那为什么在我的nginx配置中没有增加Access-Control-Allow-Origin: ‘dev.hzero.com.cn’的时候他就获取不到呢? 好了,因为我们在nginx配置中国增加了Access-Control-Allow-Origin而出现重复的Access-Control-Allow-Origin错误之后,我们在nginx配置中把这一条删除掉了,浏览器就不报错了,然后就能正常访问了。这个时候我们可以明确看到,响应头中包含了我们在nginx配置中曾经添加的 Access-Control-Allow-Origin: ‘dev.hzero.com.cn’
那为什么我们明确的已经在nginx的配置文件中删除了这条配置了,他还能在响应头中出现呢?是因为缓存吗? 是哪里的缓存呢?
- 删除浏览器数据,刷新,重新登录,响应头中依然包含。工作正常,看起来不是客户端本地缓存。
- 重启nginx服务,刷新,响应头中依然包含。工作正常,看起来不是web服务端缓存。
- 重启hzero-aip-app服务,响应头中依然包含。工作正常,看起来不是后端服务端缓存。
- 重启hzero-gateway服务,响应头中依然包含。工作正常,看起来不是后端服务端缓存。
- 究竟是哪里缓存的呢?
#Nginx容器内执行:
# curl -H ‘Origin: dev.hzero.com.cn’ \
-H ‘Authorization: Bearer 7a67e4b8-998d-4e74-a9b8-0f2da0f4da9e’ \
http://hzero-aip-app:8088/v1/open/knowledge/search-question?tenantId=0 \
-i> > >
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: dev.hzero.com.cn
Access-Control-Expose-Headers: date, content-encoding, server, etag, vary, Cache-Control, Last-Modified, content-type, transfer-encoding, connection, x-application-context, content-disposition
Access-Control-Allow-Credentials: true
Content-Type: application/json
Content-Length: 95
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0
Referrer-Policy: no-referrer
以上是不通过代理,直接访问http://hzero-aip-app:8088,在给了Origin: dev.hzero.com.cn后,返回包含了Access-Control-Allow-Origin: dev.hzero.com.cn,说明这个确实是后端服务hzero-aip-app返回的,不是nginx返回的。
说明:Access-Control-Allow-Origin: dev.hzero.com.cn 既不是 nginx 配置残留,也不是缓存,而是 后端 hzero-aip-app 的 Spring Boot CORS 框架「动态生成」的!
为什么后端配置 allowed-origins: *,却返回了具体的 dev.hzero.com.cn?
这是 Spring Boot CORS 框架的「隐式适配逻辑」,专门针对「带凭证的跨域请求」:
你的后端配置了 Access-Control-Allow-Credentials: true(响应头中已显示);
根据 CORS 标准:带凭证(Cookie/Token)的跨域请求,Access-Control-Allow-Origin 不能是 *(浏览器会拒绝);
因此 Spring Boot CORS 框架会「智能适配」:当配置 allowed-origins: * 且 allow-credentials: true 时,框架不会返回字面的 *,而是 动态返回请求头中的 Origin 值(即 dev.hzero.com.cn),既满足标准,又实现了「允许所有源 + 带凭证」的需求。
这就是一直困惑的核心原因 —— 后端配置的 * 是「逻辑上允许所有源」,但实际返回的是「请求的具体源」,而非字面的 *。
但是,但是。。。为啥第二天重启平台服务之后,他又会报CORS错误了?
- 切换到浏览器无痕模式再试,响应头中依然包含。工作正常,看起来也不是缓存问题。
- 关闭系统代理开机自启,重启服务器,重启整个平台服务,用浏览器无痕模式,再试:
问题就重现了:
第一次调用,响应标头是空的:
第二次调用,响应表头,有内容,并且有明确的错误提示:
我们把注意力集中在502 Bad Gateway上:
这个时候先看nginx中的log:
#1
172.18.0.1 – – [01/Dec/2025:06:49:45 +0000] “OPTIONS /v1/open/knowledge/search-question?tenantId=0 HTTP/1.1” 502 559 “http://dev.hzero.com.cn/” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0” “-“
#2
2025/12/01 06:49:45 [error] 32#32: *7 connect() failed (113: No route to host) while connecting to upstream, client: 172.18.0.1, server: aigc.hzero.com.cn, request: “OPTIONS /v1/open/knowledge/search-question?tenantId=0 HTTP/1.1”, upstream: “http://172.18.14.48:8088/v1/open/knowledge/search-question?tenantId=0”, host: “aigc.hzero.com.cn”, referrer: “http://dev.hzero.com.cn/”
#3
172.18.0.1 – – [01/Dec/2025:06:56:17 +0000] “GET / HTTP/1.1” 200 4959 “-” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134” “-“
172.18.0.1 – – [01/Dec/2025:06:56:18 +0000] “GET /adfs/probe HTTP/1.1” 200 4959 “-” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134” “-“
在nginx的日志中,
#1我们看到一条来自客户端 172.18.0.1的options预检请求:
这个172.18.0.1 是我们运行的docker compose网络的网关,也就是运行该docker网络的linux虚拟机的IP地址。
$ docker network inspect hzero-demo | grep -E “Subnet|Gateway”
“Subnet”: “172.18.0.0/16”,
“Gateway”: “172.18.0.1”
#2这里的upstream指的是上游服务器,说是针对来自172.18.0.1的options预检请求,去链接上游服务器172.18.14.48:8088的时候报错了。这当然会报错,因为不在一个网段内,nginx是运行在容器网络里面的,其自己的IP地址可以看到是:
$ docker inspect –format ‘{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}’ nginx-hzero
172.18.0.2
所以会报bad gateway;
这也就解释了:为什么nginx运行在linux 本机而不是容器内时,不会出问题了。
而 upstream: “http://172.18.14.48:8088/v1/open/knowledge/search-question?tenantId=0″表明nginx把反向代理的配置 hzero-aip-app这个docker容器的服务名错误的
我们来捋一捋:
把这个问豆包,豆包说上游服务器是指具体业务服务,那应该不是172.18.14.48,应该是hzero-aip-app服务乃容器对应的IP才对。
按理说容器内的nginx应该去解析容器服务名hzero-aip-app在容器网络中IP地址,为什么会去解析到容器外的linux主机IP地址?那豆包说了:Nginx 默认不会动态解析服务名(hzero-aip-app),而是在启动时缓存一次 DNS 结果。而 Docker 的服务名解析依赖内置 DNS 服务器(127.0.0.11),若 Nginx 未指定该 DNS,可能会走系统默认 DNS,导致解析错误。
在容器内执行解析命令(用nslookup或ping,若没有nslookup可先装:apt update && apt install dnsutils):
核心修复:给 Nginx 配置「Docker 内置 DNS 解析器」
Nginx 默认不会动态解析服务名(hzero-aip-app),而是在启动时缓存一次 DNS 结果。而 Docker 的服务名解析依赖内置 DNS 服务器(127.0.0.11),若 Nginx 未指定该 DNS,可能会走系统默认 DNS,导致解析错误。
在server块或http块中添加resolver配置,强制 Nginx 使用 Docker 内置 DNS,并设置短缓存(避免解析过时)
# 核心:添加Docker内置DNS解析器(必须加!)
resolver 127.0.0.11 valid=60s; # 127.0.0.11是Docker默认DNS,valid=60s定期刷新解析
resolver_timeout 5s; # DNS解析超时时间
重启nginx 后问题解决。
回顾:我们之前曾经在windows的hosts文件中添加过对hzero-aip-app的解析,如果碰到异常场景就可能出现这种问题:
异常场景 :Nginx 未配置 resolver(依赖容器默认 DNS)
此时容器内的 Nginx 会使用容器 /etc/resolv.conf 中的 DNS 顺序(优先 127.0.0.11,后备宿主机 DNS):
正常情况下,还是会通过 127.0.0.11 解析到正确的容器 IP,Windows hosts 配置依然无效;
极端情况(比如 Docker 内置 DNS 故障,概率极低):若 127.0.0.11 无法响应,Nginx 会 fallback 到宿主机 DNS;
此时宿主机 DNS 解析 hzero-aip-app 时,会先查询 Windows hosts 文件 —— 如果 hosts 中配置了该域名的映射(如 1.2.3.4),就会返回这个错误 IP,导致 Nginx 代理失败。
但这不是 “冲突”,而是 “配置不规范导致的解析异常”:根源是 Nginx 未显式配置 resolver,而非 hosts 文件和 Docker DNS 的冲突。
问题六、无痕模式下,本地存在代理(VPN)的情况下无法访问:
现象,打开浏览器的无痕模式,访问dev.hzero.com.cn,结果出现:
点继续浏览后,就被阻塞了,死活无法进入下一步,打开检查发现:返回网关错误,去访问什么一个本地的7890端口去了。
元宝分析
根本原因分析:
代理端口冲突(核心原因)
- 无痕模式未正确加载代理扩展或配置,导致请求被发送到 127.0.0.1:7890(本地代理端口)
- 该端口无活跃代理服务监听,造成网关错误(502)
解决方案:关闭本地系统代理软件。
再次访问,可以继续了。。
问题七、垃圾文件太多的问题
现象:在hzero_hfile.hfle_file表中发现大量的来自接口平台的定时任务的健康检查日志文件,每分钟产生2个文件,所以文件和文件表中的记录就非常多。
看了下定时任务的配置情况:
解决方案:
- 在 平台/调度服务/调度管理/调度任务 菜单进入,搜索“接口健康检查”先停掉接口平台健康检查的定期任务。
- 执行接口平台日志清理任务:
虽然显示完成了,但去hfle_file表看,并没有清除表中记录:
3、清除调度日志:
但实际只清除了hsdr_job_log表
并没有连带清除 hfle_file表,hfle_file表里面数据没变化.
去平台/开发管理/数据清理/数据清理配置处,执行了平台的数据清理日志和调度日志清理,也没有删除hfle_file表中的日志文件记录:
其他地方找不到系统界面上还有能清除的地方了,那么接下来只能手工清理了:
4、清除文件:在平台/文件管理/文件汇总查询的地方:
查询条件:HITF.HELTH_CHECK, 批量:100条,彻底删除,删除前,先看下minio桶里面的文件:
我看看执行后,是不是minio桶的文件也一并清除了:
实验结果,确实是minio桶的文件也一并被清除了。
不过每次100条,有4万多条要删除,这样删太慢了,接下来,直接删表删文件
select count(1) from hzero_file.hfle_file a where a.directory =’hsdr01/’ and a.file_name like ‘HITF.HEALTH_CHECK%’
–38890 条;
select count(1) from hzero_file.hfle_file a where a.directory =’hsdr01/’
–38891 条;
也就是说,目前调度任务日志都是接口平台的健康检查日志,所以一会儿去minio桶里头删除文件的时候,可以把hsdr01/0/MINO目录下的文件全部删除:
执行:
- 数据库记录删除:delete from hzero_file.hfle_file a where a.directory =’hsdr01/’
- MINO桶文件删除:进入hz-hsdr/hsdr01/0/MINIO目录,全选文件,然后点删除。
删除完成发现:hsdr01目录及其所有子目录都被删除掉了
这下OK了,只有100多个真正有用的文件记录了。
后续处理:
在 平台/调度服务/请求定义
找到接口平台健康检查,日志策略改成:仅记录异常。
但实际上这样还不够,直接禁用掉才行
这里禁用也不够,需要在调度服务/调度管理/调度任务 把接口平台的健康检查任务的自动初始化关掉:编辑,把“自动初始化”去掉,否则每次调度服务重启,会自动把这个终止的任务拉起来,而且还会把日志策略初始化成“全量记录”。
注意只有在启用状态才能编辑,非启用状态只能看详情,需要重启调度服务,才能回到启用状态,然后进行编辑。
备注(2025/12/09): 最近rebuild更新了hzero-file服务的jar包,发现清除调度日志的时候已经可以把相关联文件一起删除掉了。
问题八、文件在线编辑不能保存的问题
打开文件编辑之后,修改后点【保存并关闭】按钮后,界面没有提示信息,但后台hzero-file服务有错误日志,保存未成功。
后台日志关键错误信息是:
2025-12-08T10:31:17.514+08:00 ERROR 1 — [hzero-file] [ XNIO-1 task-2] .h.s.f.s.i.OnlyOfficeFeedBackServiceImpl : only office update text failed, callback : OnlyOfficeCallbackDTO{url=’http://onlyoffice-hzero:8800/cache/files/data/17651609109511b5aeb2_351/output.docx/output.docx?md5=1NJT1GsXAaXy9lv1ilKyVw&expires=1765161978&shardkey=17651609109511b5aeb2&filename=output.docx’, key=’17651609109511b5aeb2′, changesurl=’http://onlyoffice-hzero:8800/cache/files/data/17651609109511b5aeb2_351/changes.zip/changes.zip?md5=bK5BsAXe1FWgHbQ6muCZhw&expires=1765161978&shardkey=17651609109511b5aeb2&filename=changes.zip’, users=[2], status=2, notmodified=false} and key : 17651609109511b5aeb2
分析:该日志显示onlyoffice 通过回调API让hzero-file服务去系在onlyoffice缓存中更新后的文件时出错了。
onlyoffice容器日志也有对应的详细错误信息:
日志发给元宝分析,支持下载失败几种可能性,逐一分析:
1、网络连接问题:hzero-file的url api可以获得onlyoffice提供的编辑页面,说明网络连接没问题。
2、安全令牌(JWT)错误:我已经禁用了JWT验证,不是这个原因。
3、回调接口和逻辑是否有问题:hzero-file服务的jar包 和 onlyoffice的版本,docker-compose.yml中的配置跟非全容器环境是一样的,在非全容器环境是可以正常保存的,所以这种原因也排除掉。
4、文件路径或权限问题:OnlyOffice 服务端生成的用于更新的文件临时路径不正确,或 hzero-file 服务没有权限访问该路径,这个要仔细查一下:
我能想到的就是,挂载出来的文件目录权限是否足够,还有就是default.json中除了允许privateIP ,是否还要运行metaIP?
有个差别是我看了当初构建全容器环境的onlyoffice的挂载目录的时候是手工新建的挂载目录结构,但非全容器环境的话目录结构是容器启动时自动生成的,嗯,先尝试把原来目录结构删除掉,重启容器让目录结构也自动生成:
$ cd /d01/hzero-dockers/onlyoffice-docker
$ docker compose down
$ rm -rf /d01/hzero-dockers/volumes/onlyoffice/DocumentServer
#先注释掉docker-compose.yml中的default.json的挂载
$ docker compose up -d
#查看:相关挂载目录已经自动生成
#把default.json拷贝出来
$ docker cp onlyoffice-hzero:/etc/onlyoffice/documentserver/default.json ../volumes/onlyoffice/DocumentServer/
#更改default.json中的设置:”allowPrivateIPAddress”: false
#去掉docker-compose.yml中的default.json的挂载的注释
#重启onlyoffice容器
再次测试文件在线编辑功能,结果问题依旧,看起来不是这个原因。想到安全策略应该是优先被排查的原因,尝试把default.json中的 allowMetaIPAddress 设置为 true ,重启容器再试,结果问题依旧。看来也不是这个配置问题。
把hzero-file服务日志中的错误的文件下来连接地址,在hzero-file容器中直接访问:
# curl -v http://onlyoffice-hzero:8800/cache/files/data/176516391613405bf89d_852/output.docx/output.docx?md5=f9DLPCl-LnrOZBDQ3XcySA&expires=1765165594&shardkey=176516391613405bf89d&filename=output.docx
# * Trying 172.18.0.9:8800…
* connect to 172.18.0.9 port 8800 failed: Connection refused
* Failed to connect to onlyoffice-hzero port 8800 after 0 ms: Connection refused
* Closing connection 0
#发现居然被拒绝了,想到之前在搜default.json中的private字符串时还有个参数:blockPrivateIP 默认是true, 尝试改成: “blockPrivateIP”: false, 重启onlyoffice容器, 再测试:问题依旧。
突然发现自己傻了,8800是onlyoffice容器外访问的端口,容器网络内应该是80端口,所以对于docker网络内的hzero-file服务也要也要跟容器外实现统一8800端口访问的话,需要更改onlyoffice的nginx端口,从80改成8800端口。
那为什么在hzero-file的application.yml中配置的是8800端口,前端可以成功打开编辑文件呢?也就是成功访问了onlyoffice-hzero:8800呢? 答:那个场景中,hzero-file的API接口 url 只是把onlyoffice-hzero:8800当做拼接字符串的一部分,拼接完成后返回给前端浏览器,真正访问这个地址的是前端浏览器,这是在容器外访问的。跟这里场景不一样,这里回调的时候是hzero-file容器真的要去访问这个地址的。
尝试像以前一样,把容器内的服务的web端口 从默认80改成跟对外映射一样的8800:
备注:这种更改对于简单的Nginx服务很容易,但对于onlyoffice这样的应用未必有用,如果官方未提供更改方法,其配置和规则设置比较多的话,就不一定能改成功了,只能试一试
=======试验开始===============
$ cd /d01/hzero-dockers/onlyoffice-docker
$ docker cp onlyoffice-hzero:/etc/onlyoffice/documentserver/nginx/ds.conf ../volumes/onlyoffice/DocumentServer/
#更改端口为8800
listen 0.0.0.0:8800;
listen [::]:8800 default_server;
保存,挂载
– ${DOCKER_VOLUME_DIRECTORY:-../volumes}/onlyoffice/DocumentServer/ds.conf:/etc/onlyoffice/documentserver/nginx/ds.conf
端口映射也改成:
ports:
– “8800:8800”
重启onlyoffice容器,再测试: 这次报了个不能下载的错误:
Hzero-file后台服务日志没有错误,onlyoffice 容器日志没有对应的错误
请求 URL 是http://onlyoffice-hzero:8800/…,而onlyoffice-hzero这个域名被解析成了172.18.14.48(这是 OnlyOffice 服务对应的容器的实际 IP),8800是该服务监听的端口。所以 “远程地址 172.18.14.48:8800” 就是你这次请求要连接的目标服务端(OnlyOffice 服务)的 IP 和端口。
这没有错,对于浏览器来说,他是在容器网络外的。
对于更改onlyoffice Nginx端口这个事,豆包的分析是:
把 OnlyOffice 的 Web 端口从 80 改成 8800本身不会直接导致 403 错误,但如果端口修改时未同步更新所有相关配置,会间接引发 403(核心是「签名验证 / URL 匹配失败」),具体原因如下:
1. 最可能的原因:签名生成时的端口不匹配
OnlyOffice 缓存文件的md5签名是基于 ** 完整请求 URL(含端口)** 生成的(比如生成签名时会包含http://onlyoffice-hzero:80/…)。
若你仅修改了访问端口为 8800,但:
OnlyOffice 服务端验证签名时,会用实际请求的 URL(http://onlyoffice-hzero:8800/…)重新计算签名。
此时「生成签名的 URL(带 80)」和「实际请求的 URL(带 8800)」不一致,导致md5验证失败,直接返回 403。
这个要访问的edit.bin可以在缓存文件中看到:
那这种情况就要清缓存
# rm -rf /var/lib/onlyoffice/*
# rm -rf /var/cache/nginx/*
继续测试:
这个错误应该是onlyoffice报的错,在hzero-file服务日志和onlyoffice的容器日志中都没有错误信息。
这样,把onlyoffice容器重置一下,再试验:
先把default.json 和 ds.conf 拷贝到 d01\hzero-dockers\volumes\onlyoffice
更改docker-compose.yml的挂载位置:
volumes:
– ${DOCKER_VOLUME_DIRECTORY:-../volumes}/onlyoffice/default.json:/etc/onlyoffice/documentserver/default.json
– ${DOCKER_VOLUME_DIRECTORY:-../volumes}/onlyoffice/ds.conf:/etc/onlyoffice/documentserver/nginx/ds.conf
然后删除 d01\hzero-dockers\volumes\onlyoffice\Documentserver目录
然后重启onlyoffice容器
再次测试依然是 “打开文件时发生错误”, 看起来清缓存解决不了这个问题。
那按照元宝的说法,可能是我这种更改nginx端口的方法不对。
多次实验发现,ds.conf 这个文件不能挂载,挂载会导致混乱,而且在onlyoffice容器启动的时候,提示简历这位文件的软连接失败。
去掉这个挂载以后就可以回到成功打开文件编辑,只是保存失败的问题。
===========试验结束==================
上面的试验表明想通过更改nginx配置的方式来更改onlyoffice容器的web端口从原来的80改为8800,也不可行:onlyoffice的内部各种规则配置有点复杂,不是简单改一个Nginx配置的地方就能无故障使用。
那只能用其他方法绕了,绕的前提是不用为容器环境和非容器环境分别打包jar, 那么可以通过docker-compose.yml配置环境变量的方法,在纯容器环境的docker-compose.yml中,针对回调地址通过extra host 在hzero-file服务的容器内强行把onlyoffice-hzero解析到host机,从host机的8800端口访问,测试也不行,找不到路由。
忽然灵机一动,是不是可以通过反向代理搞定?
我们来捋一捋:
目的:容器内外通过统一域名端口访问onlyoffice的80端口
此图发给豆包,豆包基本明白我的意思,描述基本正确,漏了几点:
你漏了几点:
1、部署了3个容器,除了你说的两个,还有一个nginx容器
2、在nginx容器里面做了反向代理,把onlyoffice.hzero.com.cn 反向代理到dokcer网络内的onlyoffice容器的80端口
我要实现的目的是:在容器网络外的浏览器 和通过docker 网络内的hzero-file容器内都可以通过统一的域名onlyoffice-hzero.com.cn:80来访问 docker 网络内的onlyoffice的80端口。
你觉得我能实现目的吗?
豆包说能:
| 访问端 | 访问地址 | 实际路由链路 |
| 容器内 hzero-file | onlyoffice.hzero.com.cn:80 | hzero-file → hzero-demo 网络 → Docker DNS 解析别名 → onlyoffice 容器 80(无 nginx 中转) |
| 容器外浏览器 | onlyoffice.hzero.com.cn:80 | 浏览器 → Linux 宿主机 80 → nginx 容器 80 → 反向代理 → onlyoffice 容器 80 |
修改点:
- hzero-file 的application.yml配置中
- doc-server-url 设置成onlyoffice.hzero.com.cn(80端口默认可以省略掉)
- onlyoffice容器增加别名:onlyoffice.hzero.com.cn
networks:
hzero-demo:
aliases:
– onlyoffice.hzero.com.cn # 配置你要的域名别名(核心)
- Windows Host中增加解析:172.18.14.48 onlyoffice.hzero.com.cn(如果不是本地demo环境,是企业内网,在内部DNS中添加此解析)
- nginx容器增加反向代理配置:
server {
listen 80;
server_name onlyoffice.hzero.com.cn; # 匹配统一域名
# 反向代理到Docker网络内的onlyoffice容器80端口(直接用别名)
location / {
proxy_pass http://onlyoffice.hzero.com.cn:80; # 直接指向onlyoffice容器别名
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
}
改完后再次运行测试:
查看nginx容器日志:
2025/12/09 05:10:26 [error] 37#37: *15 connect() failed (113: No route to host) while connecting to upstream, client: 172.18.0.1, server: onlyoffice.hzero.com.cn, request: “GET /web-apps/apps/api/documents/api.js HTTP/1.1”, upstream: “http://172.18.14.48:80/web-apps/apps/api/documents/api.js”, host: “onlyoffice.hzero.com.cn”, referrer: “http://dev.hzero.com.cn/”
看起来容器内的nginx把onlyoffice.hzero.com.cn的IP地址解析错误了,应该解析到docker网络内的IP地址而不是host主机地址。为避免混淆,直接更改nginx的方向代理配置:直接用onlyoffice-hzero的容器服务名,不用别名
server {
listen 80;
server_name onlyoffice.hzero.com.cn; # 匹配统一域名
# 反向代理到Docker网络内的onlyoffice容器80端口(直接用别名)
location / {
proxy_pass http://onlyoffice-hzero:80; # 直接指向onlyoffice容器服务名
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
}
这次可以正常打开了:
修改后保存,看hzero-file的后台服务日志,已经成功,在更新表了:
下载打开该文件可以看到,更新已经生效:
问题九、如何让配置管理更清晰?
关于文件服务,我决定做些优化,让配置管理更清晰:
一、Minio文件服务:
- 在平台/文件管理/文件存储配置/MINIO 处,EndPoint还是改成:oss.hzero.com.cn:9000
- 容器服务minio-hzero添加别名:oss.hzero.com.cn
- Windows hosts 文件添域名解析:172.18.14.48 oss.hzero.com.cn #minio 文件服务域名(客户端直接预览PDF需要),去掉对minio-hzero名称的解析。
- 修数据:
文档地址
UPDATE hzero_aip.hdoc_document_version SET document_url = REPLACE(document_url, ‘minio-hzero:9000′,’oss.hzero.com.cn:9000’ );
UPDATE hzero_aip.hdoc_document_version SET source_key = REPLACE(source_key, ‘minio-hzero:9000′,’oss.hzero.com.cn:9000’ )
文件地址:
update hzero_file.hfle_file set file_url=REPLACE(file_url, ‘minio-hzero:9000′,’oss.hzero.com.cn:9000’ )
- kkfielview文件预览服务:
- 容器服务kkfileview-hzero添加别名:kkv.hzero.com.cn
之前添加的extra_hosts可以去掉了。
- Windows hosts 文件添域名解析:172.18.14.48 kkv.hzero.com.cn # 文件预览服务域名。
- 更改hzero-file文件服务的application.yml :
kk-file-view-url: http://kkv.hzero.com.cn:8012/onlinePreview # kkFileView的文件预览地址
重新构建hzero-file jar包和docker镜像
重启hzero-file服务。
这修改之后,客户端window hosts文件就保留6条解析,别的不用了:
172.18.14.48 dev.hzero.com.cn #hzero-demo环境 Nginx服务器地址
172.18.14.48 gateway.hzero.com.cn #网关的地址
172.18.14.48 aigc.hzero.com.cn # ai-app服务的反向代理
172.18.14.48 kkv.hzero.com.cn # kkfileview文件预览服务域名
172.18.14.48 oss.hzero.com.cn # minio文件服务域名(客户端直接预览PDF需要)
172.18.14.48 onlyoffice.hzero.com.cn # minio 文档在线编辑服务
关于作者:
| 昵称:Jack.shang 档案信息:jack.shang 程序员->项目经理->技术总监->项目总监->部门总监->事业部总经理->子公司总经理->集团产品运营支持 联系方式:你可以通过syfvb@hotmail.com联系作者 点击查看Jack.shang发表过的所有文章... 本文永久链接: http://blog.retailsolution.cn/archives/4858 |
对本文的评价:
