WebDAV上传必须用HttpClient而非WebClient,因其支持Digest/Bearer认证、自定义请求头、连接池复用;需设BaseAddress、正确编码路径、设置Content-Type、手动处理超时与重试,并针对不同服务验证最小闭环。

WebDAV上传必须用HttpClient,别碰WebClient
WebClient在.NET Core/.NET 5+中已不支持Digest认证和自定义PROPFIND/PUT头,而多数WebDAV服务(如Nextcloud、SharePoint Online)依赖Digest或Bearer Token,直接用WebClient会卡在401且无法调试。用HttpClient才能精细控制Authorization、If-None-Match等头,也方便复用连接池。
- 初始化
HttpClient时设BaseAddress为WebDAV根URL(如https://dav.example.com/remote.php/webdav/),避免每次拼接 - 手动添加
Authorization:Basic Base64(user:pass),或从OAuth2获取的Bearer xxx - 上传前建议先
HEAD请求目标路径,检查是否已存在,避免覆盖——WebDAV本身不保证幂等
PUT上传文件要设Content-Type,否则Nextcloud会拒收
Nextcloud、OwnCloud等对Content-Type敏感;传application/octet-stream最安全,但若传text/plain却发二进制内容,服务端可能截断或报500。注意:不是所有WebDAV服务都校验这个,但漏设是常见400原因。
- 用
ByteArrayContent或StreamContent封装文件数据 - 显式调用
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream") - 如果目标路径含中文或特殊字符(如
报告-2024.xlsx),必须用Uri.EscapeDataString()编码路径,不能只靠Uri.EscapeUriString()
删除/重命名需用MOVE和DELETE,PROPFIND查元数据
WebDAV没有“rename”方法,重命名本质是MOVE请求,Destination头必须是绝对URL(含协议和域名),相对路径会被忽略。删文件用DELETE,但某些服务(如Synology DSM)要求先PROPFIND确认存在,否则返回404而非405。
-
MOVE请求必须带Destination头,值如https://dav.example.com/remote.php/webdav/新名.pdf -
DELETE响应码204表示成功,404表示不存在——别当成失败处理 -
PROPFIND体里放最小XML:<?xml version="1.0"?><d:propfind xmlns:d="DAV:"><d:prop><d:getlastmodified/><d:getcontentlength/></d:prop></d:propfind>,避免全量属性拖慢响应
超时和重试必须自己加,WebDAV没内置机制
WebDAV操作常因网络抖动或服务端限流失败(尤其大文件上传),但HttpClient默认无重试,超时默认100秒也不够传百兆文件。不处理会导致上传中途静默失败。
- 设置
HttpClient.Timeout = TimeSpan.FromMinutes(10),别用默认值 - 对
PUT/MOVE这类非幂等操作,仅对5xx和连接异常重试;4xx(如409 Conflict)直接抛出 - 用
Polly库最省事:Policy.HandleResult<httpresponsemessage>(r => !r.IsSuccessStatusCode && r.StatusCode >= 500).WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(2))</httpresponsemessage>
WebDAV路径权限、锁机制、分块上传支持度因服务而异,同一套代码在Nextcloud能跑,在SharePoint可能卡在OPTIONS预检——实际部署前,务必拿目标环境的真实URL跑通PROPFIND + PUT + DELETE最小闭环。










