7. 写锁 (Write Lock)
本节描述写锁,这是本规范中定义的唯一锁类型。写锁是授予锁所有者修改资源权利的锁。锁所有者是创建锁的主体。
7.1 写锁和属性 (Write Locks and Properties)
虽然没有写锁的人不能更改资源的内容,但他们可以修改资源的死属性。例如,这允许主体在不需要写访问权限的情况下向锁定的资源添加注释。
活属性通常具有由服务器强制执行的语义。因此,服务器可以自行决定是否以及如何允许在资源被锁定时更改活属性。例如,即使资源被锁定,服务器也可以允许修改活属性。
7.2 避免丢失更新 (Avoiding Lost Updates)
写锁的目的是防止丢失更新。当多个主体在没有协调的情况下尝试修改资源时,会发生丢失更新,导致一个或多个主体的更改被后续更新覆盖。
写锁提供了序列化机制:只有锁持有者可以修改锁定的资源。这通过确保修改按顺序而不是并发发生来防止丢失更新问题。
丢失更新场景示例 (Example Lost Update Scenario) (无锁定):
- 用户A检索资源版本1
- 用户B检索资源版本1
- 用户A修改并保存 → 创建版本2
- 用户B修改(基于版本1)并保存 → 创建版本3,覆盖A的更改
使用写锁 (With Write Lock):
- 用户A锁定资源
- 用户B尝试修改 → 收到423 Locked错误
- 用户A修改并解锁
- 用户B现在可以锁定和修改
7.3 写锁和未映射的URL (Write Locks and Unmapped URLs)
对未映射URL的成功LOCK请求会创建一个被锁定的空资源。此机制允许客户端在创建资源内容之前保留URL。
创建锁定的空资源时:
- 资源没有内容(零长度实体)
- 资源使用指定的锁锁定
- 后续的PUT或MKCOL可以向资源添加内容
- 必须在PUT或MKCOL请求中提交锁令牌
此"锁空资源 (lock-null resource)"机制在附录D中详细描述。
7.4 写锁和集合 (Write Locks and Collections)
集合上的写锁锁定集合资源本身,防止修改集合的成员资格(添加或删除内部成员)。
当深度无限锁应用于集合时:
- 集合本身被锁定
- 所有内部成员被锁定
- 所有后代资源递归锁定
- 添加到集合的新成员自动锁定
锁继承 (Lock Inheritance): 当新资源添加到锁定的集合(深度无限)时,新资源从父集合继承锁。
示例 (Example):
集合 /folder/ 使用 Depth: infinity 锁定
- 无法向 /folder/ 添加新成员
- 无法修改 /folder/file1.txt
- 无法删除 /folder/subfolder/
- 无法修改 /folder/subfolder/file2.txt
7.5 写锁和If请求头 (Write Locks and the If Request Header)
客户端使用If请求头提交锁令牌。此头允许基于锁令牌存在的方法条件执行。
If头语法支持:
- 单个锁令牌
- 多个锁令牌(用于多个锁)
- 标记列表(将令牌与特定URL关联)
- NOT条件(要求不存在锁)
7.5.1 示例 - 写锁和COPY (Example - Write Lock and COPY)
COPY /source HTTP/1.1
Host: example.com
Destination: http://example.com/destination
If: \`http://example.com/destination\` (<opaquelocktoken:token123>)
此请求将/source复制到/destination,但仅当客户端持有/destination的锁令牌时。
7.5.2 示例 - 删除锁定集合的成员 (Example - Deleting a Member of a Locked Collection)
DELETE /folder/file.txt HTTP/1.1
Host: example.com
If: \`http://example.com/folder/\` (<opaquelocktoken:folder-token>)
要删除锁定集合的成员,客户端必须提交集合的锁令牌。
7.6 写锁和COPY/MOVE (Write Locks and COPY/MOVE)
COPY方法在目标位置创建新资源。新资源不会自动锁定,即使源被锁定。锁不会被复制。
MOVE方法在语义上等同于COPY后跟DELETE。移动资源时,源上的锁被删除。目标不会自动锁定。
如果COPY或MOVE的目标被锁定,客户端必须提交适当的锁令牌来覆盖目标。
7.7 刷新写锁 (Refreshing Write Locks)
锁具有有限的生命周期。为了防止过早的锁过期,客户端可以通过提交带有以下内容的LOCK请求来刷新锁:
If头中的相同锁令牌- 无请求主体(或空的
lockinfo元素)
服务器响应新的超时值。锁刷新允许长期编辑会话而不会锁过期。
锁刷新示例 (Example Lock Refresh):
LOCK /resource HTTP/1.1
Host: example.com
If: (<opaquelocktoken:token123>)
Timeout: Second-3600
服务器延长锁超时并返回新的过期时间。