1203 字
6 分钟
WebDAV 协议 HTTP 请求内容初见
核心方法(Methods)
| 场景 | 方法 | 关键请求头 | 典型响应 | 说明 |
|---|---|---|---|---|
| 探测服务能力 | OPTIONS | — | 200 OK,DAV 响应头 | DAV 响应头会列出支持的扩展(如 1,2,3、calendar-access 等)。 |
| 列目录/查属性 | PROPFIND | Depth: 0/1/infinity;Content-Type: application/xml | 207 Multi-Status (XML) | 获取资源(文件/目录)的属性。Depth:1 列出当前目录 + 一层子项最常用。 |
| 修改/新增属性 | PROPPATCH | Content-Type: application/xml | 207 Multi-Status | 设置/删除自定义或标准属性(如 displayname)。 |
| 创建目录 | MKCOL | — | 201 Created | 仅能在目标路径创建“集合”(文件夹)。父级不存在会 409 Conflict。 |
| 上传/新建文件 | PUT | If-None-Match: *(防覆盖,推荐);Content-Type | 201 Created/204 No Content | 覆盖已存在资源:204。用 If-None-Match:* 可避免误覆盖(否则可能 412)。 |
| 下载文件 | GET | Range(可选) | 200 OK/206 Partial Content | 标准 HTTP 下载;多数服务器支持范围请求。 |
| 查看元信息 | HEAD | — | 200 OK | 与 GET 类似但无响应体。可拿到 ETag、Last-Modified 等。 |
| 删除 | DELETE | — | 204 No Content | 目录需为空(有的服务器支持递归删,否则 409)。 |
| 复制 | COPY | Destination;Overwrite: T/F | 201 Created/204 No Content | 目标存在且 Overwrite:F → 412 Precondition Failed。 |
| 移动/改名 | MOVE | Destination;Overwrite: T/F | 201/204 | 同 COPY 的覆盖规则;同卷“改名”就是 MOVE 到同目录新名。 |
| 加锁 | LOCK | Content-Type: application/xml;Timeout: Second-600(可选) | 200 OK(含锁 token) | 返回 lockdiscovery 和 <D:locktoken>(形如 opaquelocktoken:...)。 |
| 解锁 | UNLOCK | Lock-Token: <opaquelocktoken:...> | 204 No Content | 解锁后其他客户端可写。 |
CalDAV/CardDAV 会再扩展
REPORT、MKCALENDAR等;若只关心通用 WebDAV,上表已够用。
关键请求/响应头
Depth: 0 | 1 | infinityPROPFIND/REPORT常用。0仅当前资源,1包含一层子项,infinity可能被服务器禁止以防重载。Destination: https://server/target/pathCOPY/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.1Host: example.comDepth: 1Content-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-StatusContent-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.1Host: example.com响应:
HTTP/1.1 201 Created3) 上传文件(安全防覆盖,PUT + If-None-Match:*)
PUT /dav/new-folder/readme.txt HTTP/1.1Host: example.comContent-Type: text/plain; charset=utf-8If-None-Match: *Content-Length: 15
Hello WebDAV!\n存在同名文件时:
HTTP/1.1 412 Precondition Failed4) 移动/改名(MOVE)
MOVE /dav/new-folder/readme.txt HTTP/1.1Host: example.comDestination: https://example.com/dav/new-folder/README.txtOverwrite: T响应:
HTTP/1.1 201 Created # 或 204 No Content(覆盖)5) 复制(COPY)且不允许覆盖
COPY /dav/src.bin HTTP/1.1Host: example.comDestination: https://example.com/dav/copy.binOverwrite: F目标已存在 → 412 Precondition Failed。
6) 加锁与解锁(LOCK / UNLOCK)
加锁:
LOCK /dav/report.docx HTTP/1.1Host: example.comContent-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 OKContent-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.1Host: example.comLock-Token: <opaquelocktoken:5f2a-...-9a>响应:204 No Content
常见属性(Properties)
标准 DAV: 命名空间中最常用的只读/只写属性:
- 只读:
getcontentlength(字节数)、getlastmodified、getetag、resourcetype(文件为空、目录为<D:collection/>) - 可写(依服务器):
displayname、自定义扩展属性(自有命名空间)
PROPFIND 要么列举 <D:prop> 中的属性,要么用 <D:allprop/>(不推荐,容易很重)。
典型操作流程(实践指北)
-
列目录:
PROPFIND Depth:1→ 展示子项及属性(名称、大小、ETag)。 -
新建文件夹:
MKCOL /path/new/。 -
上传文件:
PUT,为安全加If-None-Match:*;若要并发安全,用If-Match:"<etag>"。 -
改名/移动:
MOVE+Destination,控制Overwrite。 -
复制:
COPY+Destination。 -
并发与协作:
- 编辑前
LOCK(拿到opaquelocktoken), - 写入时携带条件头(
If/If-Match), - 完成后
UNLOCK。
- 编辑前
-
删除:
DELETE,注意是否需要先清空目录。
调试与兼容性要点
- 编码与路径:URL 需要正确转义(空格等字符);避免奇异字符引发服务器拒绝。
- 认证:Basic/Digest/Bearer/OAuth 由服务器决定;失败是
401或403。 - 大目录/深层遍历:
Depth:infinity可能被禁;分页或分层遍历更稳。 207解析:返回体是 XML 多状态,每个<D:response>对应一个资源,解析<D:href>与<D:propstat>。- ETag/条件请求:强烈建议在批量同步/覆盖场景使用,以避免数据竞争。
- 存储配额:遇到
507就是配额/磁盘爆满。 - 服务器差异:各实现(Apache mod_dav、nginx+第三方、SabreDAV、Nextcloud、IIS WebDAV)对特性/深度/锁支持略有不同,遇到问题看
OPTIONS的DAV、Allow。
WebDAV 协议 HTTP 请求内容初见
https://blog.lpkt.cn/posts/webdav-protocol-simple/