修复方案:在 routes/webdav.py 中添加了一个 WSGI 中间件包装函数,在请求到达 WsgiDAV 前:

1. 读取 X-Forwarded-Proto 设置正确的 wsgi.url_scheme
  2. 将 Destination 头中的外部 scheme/host 重写为内部实际值
This commit is contained in:
朱潮 2026-03-09 18:51:08 +08:00
parent 5d97be9557
commit 38c5d1e622

View File

@ -6,6 +6,7 @@ WebDAV 文件管理路由
"""
from pathlib import Path
from urllib.parse import urlparse, urlunparse
from wsgidav.wsgidav_app import WsgiDAVApp
from wsgidav.fs_dav_provider import FilesystemProvider
@ -56,4 +57,36 @@ config = {
},
}
wsgidav_app = WsgiDAVApp(config)
_wsgidav_app = WsgiDAVApp(config)
def wsgidav_app(environ, start_response):
"""WSGI 中间件:处理反向代理场景下 Destination 头的 scheme/host 不匹配问题。
当服务运行在 HTTPS 反向代理后面时客户端发送的 Destination 头包含外部 URL
https://example.com/webdav/docs/new-name WsgiDAV 内部看到的是 HTTP
这个中间件将 Destination 头重写为与内部请求一致的 scheme host
"""
# 从 X-Forwarded 头获取外部信息,并确保 wsgi.url_scheme 正确
forwarded_proto = environ.get("HTTP_X_FORWARDED_PROTO")
if forwarded_proto:
environ["wsgi.url_scheme"] = forwarded_proto
# 重写 Destination 头:将外部 scheme/host 替换为内部实际值
destination = environ.get("HTTP_DESTINATION")
if destination:
parsed = urlparse(destination)
# 用内部实际的 scheme 和 host 替换
internal_scheme = environ.get("wsgi.url_scheme", "http")
internal_host = environ.get("HTTP_HOST", environ.get("SERVER_NAME", "localhost"))
rewritten = urlunparse((
internal_scheme,
internal_host,
parsed.path,
parsed.params,
parsed.query,
parsed.fragment,
))
environ["HTTP_DESTINATION"] = rewritten
return _wsgidav_app(environ, start_response)