1203 字
6 分钟
WebDAV 协议 HTTP 请求内容初见
2025-10-17

核心方法(Methods)#

场景方法关键请求头典型响应说明
探测服务能力OPTIONS200 OKDAV 响应头DAV 响应头会列出支持的扩展(如 1,2,3calendar-access 等)。
列目录/查属性PROPFINDDepth: 0/1/infinityContent-Type: application/xml207 Multi-Status (XML)获取资源(文件/目录)的属性。Depth:1 列出当前目录 + 一层子项最常用。
修改/新增属性PROPPATCHContent-Type: application/xml207 Multi-Status设置/删除自定义或标准属性(如 displayname)。
创建目录MKCOL201 Created仅能在目标路径创建“集合”(文件夹)。父级不存在会 409 Conflict
上传/新建文件PUTIf-None-Match: *(防覆盖,推荐);Content-Type201 Created/204 No Content覆盖已存在资源:204。用 If-None-Match:* 可避免误覆盖(否则可能 412)。
下载文件GETRange(可选)200 OK/206 Partial Content标准 HTTP 下载;多数服务器支持范围请求。
查看元信息HEAD200 OKGET 类似但无响应体。可拿到 ETagLast-Modified 等。
删除DELETE204 No Content目录需为空(有的服务器支持递归删,否则 409)。
复制COPYDestinationOverwrite: T/F201 Created/204 No Content目标存在且 Overwrite:F412 Precondition Failed
移动/改名MOVEDestinationOverwrite: T/F201/204COPY 的覆盖规则;同卷“改名”就是 MOVE 到同目录新名。
加锁LOCKContent-Type: application/xmlTimeout: Second-600(可选)200 OK(含锁 token)返回 lockdiscovery<D:locktoken>(形如 opaquelocktoken:...)。
解锁UNLOCKLock-Token: <opaquelocktoken:...>204 No Content解锁后其他客户端可写。

CalDAV/CardDAV 会再扩展 REPORTMKCALENDAR 等;若只关心通用 WebDAV,上表已够用。


关键请求/响应头#

  • Depth: 0 | 1 | infinity PROPFIND/REPORT 常用。0 仅当前资源,1 包含一层子项,infinity 可能被服务器禁止以防重载。
  • Destination: https://server/target/path COPY/MOVE 必需。必须是绝对 URI。
  • Overwrite: T | F 复制/移动时是否允许覆盖目标。F 且目标存在 → 412 Precondition Failed
  • If-None-Match: * PUT 防止覆盖已有文件。
  • If-Match: "<etag>" / If: (...)(WebDAV 条件头) 基于 ETag 或锁令牌的条件更新,避免并发覆盖。
  • Lock-Token: <opaquelocktoken:...> UNLOCK 必需,部分写操作在持锁时也会在 If 头里携带。
  • DAV(响应头) 服务器返回支持的 WebDAV 类别:1(基础属性/集合等)、2(锁/LOCK/UNLOCK)、3(高级扩展)。

常见返回码#

  • 207 Multi-Status:XML 多资源结果(PROPFIND/PROPPATCH/REPORT)。
  • 201 Created / 204 No Content:创建成功 / 覆盖成功。
  • 409 Conflict:父目录不存在或语义冲突。
  • 412 Precondition Failed:条件请求未满足(如 If-None-Match:* 但目标已存在、Overwrite:F 但目标存在)。
  • 423 Locked:资源被锁。
  • 507 Insufficient Storage:空间不足。
  • 401/403:鉴权/权限问题。

最小请求示例(原始 HTTP 摘要)#

1) 列目录(PROPFIND Depth:1#

PROPFIND /dav/photos/ HTTP/1.1
Host: example.com
Depth: 1
Content-Type: application/xml
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:displayname/>
<D:getcontentlength/>
<D:getlastmodified/>
<D:resourcetype/>
<D:getetag/>
</D:prop>
</D:propfind>

典型响应(节选):

HTTP/1.1 207 Multi-Status
Content-Type: application/xml; charset="utf-8"
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>/dav/photos/</D:href>
<D:propstat>
<D:prop>
<D:displayname>photos</D:displayname>
<D:resourcetype><D:collection/></D:resourcetype>
<D:getetag>"d41d8cd98f..."</D:getetag>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<!-- 子项若干 ... -->
</D:multistatus>

2) 创建目录(MKCOL#

MKCOL /dav/new-folder/ HTTP/1.1
Host: example.com

响应:

HTTP/1.1 201 Created

3) 上传文件(安全防覆盖,PUT + If-None-Match:*#

PUT /dav/new-folder/readme.txt HTTP/1.1
Host: example.com
Content-Type: text/plain; charset=utf-8
If-None-Match: *
Content-Length: 15
Hello WebDAV!\n

存在同名文件时:

HTTP/1.1 412 Precondition Failed

4) 移动/改名(MOVE#

MOVE /dav/new-folder/readme.txt HTTP/1.1
Host: example.com
Destination: https://example.com/dav/new-folder/README.txt
Overwrite: T

响应:

HTTP/1.1 201 Created # 或 204 No Content(覆盖)

5) 复制(COPY)且不允许覆盖#

COPY /dav/src.bin HTTP/1.1
Host: example.com
Destination: https://example.com/dav/copy.bin
Overwrite: F

目标已存在 → 412 Precondition Failed

6) 加锁与解锁(LOCK / UNLOCK#

加锁:

LOCK /dav/report.docx HTTP/1.1
Host: example.com
Content-Type: application/xml; charset="utf-8"
Timeout: Second-600
<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D='DAV:'>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
<D:owner>
<D:href>mailto:you@example.com</D:href>
</D:owner>
</D:lockinfo>

响应(节选,含锁 token):

HTTP/1.1 200 OK
Content-Type: application/xml
<D:prop xmlns:D="DAV:">
<D:lockdiscovery>
<D:activelock>
<D:locktype><D:write/></D:locktype>
<D:lockscope><D:exclusive/></D:lockscope>
<D:depth>0</D:depth>
<D:timeout>Second-600</D:timeout>
<D:locktoken>
<D:href>opaquelocktoken:5f2a-...-9a</D:href>
</D:locktoken>
</D:activelock>
</D:lockdiscovery>
</D:prop>

解锁:

UNLOCK /dav/report.docx HTTP/1.1
Host: example.com
Lock-Token: <opaquelocktoken:5f2a-...-9a>

响应:204 No Content


常见属性(Properties)#

标准 DAV: 命名空间中最常用的只读/只写属性:

  • 只读:getcontentlength(字节数)、getlastmodifiedgetetagresourcetype(文件为空、目录为 <D:collection/>
  • 可写(依服务器):displayname、自定义扩展属性(自有命名空间)

PROPFIND 要么列举 <D:prop> 中的属性,要么用 <D:allprop/>(不推荐,容易很重)。


典型操作流程(实践指北)#

  1. 列目录PROPFIND Depth:1 → 展示子项及属性(名称、大小、ETag)。

  2. 新建文件夹MKCOL /path/new/

  3. 上传文件PUT,为安全加 If-None-Match:*;若要并发安全,用 If-Match:"<etag>"

  4. 改名/移动MOVE + Destination,控制 Overwrite

  5. 复制COPY + Destination

  6. 并发与协作

    • 编辑前 LOCK(拿到 opaquelocktoken),
    • 写入时携带条件头(If / If-Match),
    • 完成后 UNLOCK
  7. 删除DELETE,注意是否需要先清空目录。


调试与兼容性要点#

  • 编码与路径:URL 需要正确转义(空格等字符);避免奇异字符引发服务器拒绝。
  • 认证:Basic/Digest/Bearer/OAuth 由服务器决定;失败是 401403
  • 大目录/深层遍历Depth:infinity 可能被禁;分页或分层遍历更稳。
  • 207 解析:返回体是 XML 多状态,每个 <D:response> 对应一个资源,解析 <D:href><D:propstat>
  • ETag/条件请求:强烈建议在批量同步/覆盖场景使用,以避免数据竞争。
  • 存储配额:遇到 507 就是配额/磁盘爆满。
  • 服务器差异:各实现(Apache mod_dav、nginx+第三方、SabreDAV、Nextcloud、IIS WebDAV)对特性/深度/锁支持略有不同,遇到问题看 OPTIONSDAVAllow
WebDAV 协议 HTTP 请求内容初见
https://blog.lpkt.cn/posts/webdav-protocol-simple/
作者
lollipopkit
发布于
2025-10-17
许可协议
CC BY-NC-SA 4.0