七个新方法各配几个新状态码:207 一批结果、422 格式没错但内容不行、423 被锁住、 424 因为别的失败所以没做、507 存储不够。其中 423 和 409 的边界最容易搞混。
上一节把 207 看清楚了,这一节把方法挨个跑一遍,顺带把「删除一个目录」这条最麻烦的规则说清楚。
一、七个方法,一张表
PROPFIND 读属性、PROPPATCH 写属性、MKCOL 建集合、COPY 复制、MOVE 移动或改名、
LOCK 加锁、UNLOCK 解锁。前两个共用 207,后五个多用 201/204。
COPY 和 MOVE 的目标位置放哪?放在 Destination 首部里,是个完整 URI,不是相对路径。
这一点常常被写错。
LOCK 成功后会回一个 Lock-Token 首部,值长这样:<opaquelocktoken:...>。
之后所有对这份资源的写操作,都得带上这个令牌,否则一律 423。
二、五个新状态码
207 Multi-Status:一批结果,正文 XML 里每条自带状态。
422 Unprocessable Entity:请求体语法没毛病,但内容说不通。
典型场景是 XML 里写了「给一个不存在的属性赋值」。
注意它和 400 的分界:400 是「我看不懂」,422 是「看懂了但不认」。
423 Locked:资源被锁着。
Demo 里锁住 a.txt 之后再去 PUT,回的就是 423,响应里会把令牌带回来告诉你该带哪个。
424 Failed Dependency:这件事本身没错,但因为「它依赖的那件事」失败了,所以没做。
它几乎总是出现在 207 的某一条结果里,不单独出现。
507 Insufficient Storage:服务器存不下了。
注意它和 4.5.2 的 503 不是一回事:503 是「我现在忙不过来,等会儿再来」,507 是「我这里放不下了」。
三、删除一个目录:要么全删,要么别删
这是 WebDAV 里最容易被忽略的一条。
DELETE 一个集合时,规范要求按「深度无限」处理,并且整体成功或整体不动。
如果里面有一个文件删不掉(比如被别人锁着),服务端不能删一半留一半,而应该回 207,把能删的、
不能删的分条列出来,失败的那几条给 424,理由写「依赖失败」。
这条规则在真实系统里很重要:删一半的目录比不删更糟,因为调用方没法判断现在到底是什么状态。
同一套思路在 4.x 那批码里也有影子——409、412 都是在说「当前状态不对,所以我不动」。
这是 HTTP 一贯的做法:宁可整个失败,也不留下半成品。
四、动手 Demo:十三个请求,八种状态码
还是那个本机 WebDAV 服务端,按顺序走一遍:建集合、重名再建、新建文件、覆盖文件、复制、改名、加锁、 锁着还去写、改属性、两次解锁、删除、查不存在的资源。每一行都是一个真请求回的真状态码。
if method == u'PUT':
if st.get(u'_lock') and hdrs.get(u'if', u'') != u'(<%s>)' % st[u'_lock']:
return 423 # 锁着,别写
if method == u'MKCOL':
if path in st:
return 405 # 重名,不是 409
实跑输出:
--------------------------------------------------------------------
WebDAV 新增的方法各回什么状态码
--------------------------------------------------------------------
方法 路径 状态 说明
MKCOL /files 201 第一次建集合
MKCOL /files 405 再建一次同名
PUT /files/a.txt 201 新建资源
PUT /files/a.txt 204 覆盖已有资源
COPY /files/a.txt 201 复制到新路径
MOVE /files/c.txt 201 改名换路径
LOCK /files/a.txt 200 加排他锁
PUT /files/a.txt 423 锁着还去写
PROPPATCH /files/a.txt 207 改属性
UNLOCK /files/a.txt 409 拿错令牌解锁
UNLOCK /files/a.txt 204 拿对的令牌解锁
DELETE /files/m.txt 204 删掉资源
PROPFIND /files/gone.txt 404 查不存在的资源
LOCK 发的令牌 <opaquelocktoken:71df91ca>
请求总数 13 个
出现过的状态码 200(1 次)、201(4 次)、204(3 次)、207(1 次)、404(1 次)、405(1 次)、409(1 次)、423(1 次)
三个不常见但很说明问题的码:
201 建成了,MKCOL、PUT 新建、COPY、MOVE 都回这个;
207 一批结果装在一个响应里,PROPPATCH 回的就是它;
423 资源被锁着,没带对令牌的写入一律拒绝。
另外 409 出在解锁那一行:令牌对不上就直说,不给「大概是同一把」的余地。
规范里还有 422、424、507 三个码,这个服务端没实现,所以没出现——
我不编它们的结果,要看只能去查 RFC 4918 的原文。
MKCOL 建重名回的是 405 不是 409,这一点和直觉不一样,是规定。
建集合 201,重名再建 405。
注意是 405 不是 409——RFC 4918 明写 MKCOL 只能作用在「还没有资源的 URL」上,
已经有了就是「方法用错地方」。
新建资源 201,覆盖已有资源 204。同一个 PUT,回什么码取决于它之前存不存在。
COPY 201、MOVE 201、LOCK 200、PROPPATCH 207、DELETE 204、查不存在的资源 404。
锁着还去写回 423;拿错令牌解锁回 409,拿对回 204。
这两行放在一起最能说明问题:锁是真的会拦人,解锁也真的会验令牌。
十三个请求共出现 8 种状态码:200、201、204、207、404、405、409、423。
其中 201 出现 4 次、204 出现 3 次,其余各 1 次。
30 秒实验
- 把
MKCOL重名那个分支改成回 409,想想调用方会怎么误解。 - 试试对
/files目录发DELETE,看你的实现是整体删还是报错。 - 想一想:
423和403都是「不让你写」,区别在哪?
常见误区
- 「MKCOL 重名应该回 409」——规范写的是 405,因为方法用错了位置。
- 「423 和 403 是一回事」——403 是「不许」,423 是「先解锁再写」,锁一解就能写。
- 「删目录能删多少算多少」——规范要求整体成功或整体不动,部分失败要用 207 报。
自测三问(点开对答案)
1. MKCOL 建一个已存在的集合,回什么状态码? —— 405 Method Not Allowed,不是 409。 2. 422 和 400 的区别是什么? —— 400 是「我看不懂」,422 是「看懂了但内容不认」。 3. 两个客户端同时改一个文件,WebDAV 靠什么拦? —— LOCK 加锁,写操作必须带 Lock-Token,不带就回 423。第九章讲完了。下一章换个方向:HTTP 传的那些网页,本身是用什么做出来的。
- ☐ (本章完,下一节 10.1.1 Web页面几乎全由HTML构建)