WebDAV 是给 HTTP 加的一组方法和状态码,目的是让 Web 服务器能当网盘用:列目录、建目录、复制、 改名、加锁。它的招牌是 207 Multi-Status——一个请求回来一批对象的状态。
前面三个协议都在改「传输」。WebDAV 是最朴素的一条路:协议不动,只给它添几个动词。 这一节看它添了什么、怎么回话。
一、把服务器当硬盘用
HTTP 本来就能 GET 和 PUT,理论上已经能读写文件了。
但真当网盘用的时候,你会发现缺一堆动作:怎么列目录?怎么建目录?怎么复制一个文件?
怎么防止两个人同时改同一份?
WebDAV 就是补这些的。它在 1999 年成为 RFC 2518,后来修订成 RFC 4918,一直用到现在。
现实里你可能天天在用而不自知:Windows 的「映射网络驱动器」、macOS 访达里的「连接服务器」、
Office 的共享编辑,底层都可能是 WebDAV。它不显眼,但活得比 SPDY 久多了。
二、加了七个方法
PROPFIND 读属性(列目录就是读一批属性)、PROPPATCH 写属性、MKCOL 建集合(相当于建目录)、
COPY 复制、MOVE 改名或挪位置、LOCK 加锁、UNLOCK 解锁。
加上原有的 OPTIONS、GET、HEAD、PUT、DELETE,一共 12 个方法。
Demo 里 OPTIONS 回的 Allow 首部把这 12 个全列了出来。
注意 OPTIONS 的响应里还有一行 DAV: 1, 2。
这个首部是 WebDAV 的身份证:1 表示支持基本功能,2 表示支持锁定。看到它,客户端才敢往下走。
三、207 是它的招牌
普通 HTTP 一次请求只有一个结果,所以一个状态码就够。
但 PROPFIND 一次要回一个目录下所有文件的属性——每个文件都可能成功或失败。
所以 WebDAV 造了一个新码:207 Multi-Status。
状态行写 207,正文是一段 XML,里面一个 <D:response> 一条结果,每条自带自己的 <D:status>。
Demo 里 Depth: 0 只要自己那一条,回 400 字节、1 个 response;
Depth: 1 要自己和直接子项,回 1018 字节、3 个 response。
一个请求装了三份结果,这在 HTTP/1.1 里是没有的表达方式。
注意每个 <D:response> 里用 href 指对象——那是路径,不是标题。
客户端拿到就是拿路径去对,所以路径里的编码不能随便动。
四、动手 Demo:OPTIONS 问能力,PROPFIND 要清单
一个本机 WebDAV 服务端,内存里存几个资源。
先 OPTIONS 问它支持什么,再建一个集合、放两个文件,
然后用 Depth: 0 和 Depth: 1 各 PROPFIND 一次,把 207 的正文原样打出来。
def prop_xml(path, item):
body, kind, mt = item
rt = u'<D:collection/>' if kind == u'col' else u''
return (u'<D:response><D:href>%s</D:href><D:propstat><D:prop>'
u'<D:displayname>%s</D:displayname>'
u'<D:getcontentlength>%d</D:getcontentlength>'
u'<D:getlastmodified>%s</D:getlastmodified>'
u'<D:resourcetype>%s</D:resourcetype>'
u'</D:prop><D:status>HTTP/1.1 200 OK</D:status>'
u'</D:propstat></D:response>' % (path, name, len(body), mt, rt))
实跑输出:
--------------------------------------------------------------------
OPTIONS 与 PROPFIND:207 里装的是什么
--------------------------------------------------------------------
OPTIONS 状态行 HTTP/1.1 200 OK
DAV 首部 1, 2
Allow 首部长度 85 字节
Allow 列出的方法 共 12 个
这 12 个方法里,只有前 3 个是 HTTP/1.1 本来有的(OPTIONS、GET、HEAD),
剩下 9 个全是 WebDAV 加上去的。DAV: 1, 2 里那个 2 表示支持锁定。
Depth: 0 的状态行 HTTP/1.1 207 Multi-Status
Depth: 0 的 Content-Type application/xml; charset="utf-8"
Depth: 0 正文 400 字节,1 个 response
Depth: 1 的状态行 HTTP/1.1 207 Multi-Status
Depth: 1 正文 1018 字节,3 个 response
Depth: 1 回来的原文(换行只是为了好看):
<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>/dav</D:href>
<D:propstat>
<D:prop>
<D:displayname>dav</D:displayname>
<D:getcontentlength>0</D:getcontentlength>
<D:getlastmodified>Sun, 25 Oct 2026 07:03:59 GMT</D:getlastmodified>
<D:resourcetype>
<D:collection/>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/dav/a.txt</D:href>
<D:propstat>
<D:prop>
<D:displayname>a.txt</D:displayname>
<D:getcontentlength>5</D:getcontentlength>
<D:getlastmodified>Sun, 25 Oct 2026 07:03:59 GMT</D:getlastmodified>
<D:resourcetype>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/dav/b.txt</D:href>
<D:propstat>
<D:prop>
<D:displayname>b.txt</D:displayname>
<D:getcontentlength>7</D:getcontentlength>
<D:getlastmodified>Sun, 25 Oct 2026 07:03:59 GMT</D:getlastmodified>
<D:resourcetype>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
整个 XML 里 <D: 出现 29 次
注意两点:状态码是 207,不是 200;正文是 XML,一个响应里塞了多条结果。
这就是 WebDAV 的招牌做法——一次请求回一批对象的状态,
每个对象自带一条 status,所以整批里可以有的成功有的失败。
OPTIONS 回 200,带 DAV: 1, 2,Allow 首部 85 字节、列了 12 个方法。
这一问一答就是客户端「探能力」的标准动作。
PROPFIND 两次都回 207 Multi-Status,Content-Type 是 application/xml; charset="utf-8"。
状态码不是 200——这一点最容易记错。
Depth: 0 回 400 字节 / 1 个 response,Depth: 1 回 1018 字节 / 3 个 response。
Depth 就是「要几层」,它是个请求首部,不是路径参数。
XML 里 <D: 出现 29 次。
看着啰嗦,但它换来的是「一个响应里装 N 条结果,每条自带状态」——这正是 WebDAV 存在的理由。
30 秒实验
- 把
Depth: 1改成Depth: infinity,看服务端该怎么处理(很多实现直接拒绝)。 - 给
PROPFIND的请求体里只点名要getcontentlength,看返回会不会瘦下来。 - 想一想:为什么
PROPFIND不用 GET?用 GET 能不能表达「列一批属性」?
常见误区
- 「WebDAV 是一个新协议」——它是 HTTP 的扩展,方法和状态码都是加在 HTTP 上的。
- 「207 等于成功」——207 只表示「一批结果回来了」,每条结果要自己看 status。
- 「PROPFIND 就是 GET 目录」——GET 一个目录在多数服务器上是 403 或 404。
自测三问(点开对答案)
1. WebDAV 一共给 HTTP 加了几个方法?分别是什么? —— 七个:PROPFIND、PROPPATCH、MKCOL、COPY、MOVE、LOCK、UNLOCK。 2. 207 这个状态码是干什么的? —— 一次返回一批对象的状态,正文是 XML,每条结果自带 status。 3. `DAV: 1, 2` 里的 2 表示什么? —— 支持锁定(LOCK/UNLOCK)。1 表示支持基本功能。方法有了,回话的码也得有。下一节把这些方法挨个跑一遍,看各回什么。
- ☐ (本节完,下一节 9.5.2 WebDAV内新增的方法及状态码)