Copyright © 2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
Linked Web Storage Protocol 规范旨在以互操作的方式,为应用程序提供对外部存储数据的安全且经许可的访问。
本节描述本文档在发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准和草案 索引中找到。
这是一项非官方提案。
本文档由 Linked Web Storage 工作 组作为 工作草案发布,并使用 推荐标准 轨道。
作为 工作草案发布并不意味着 W3C 及其成员认可该文档。
这是一份草案文档,可能随时被其他文档更新、替换或废弃。 除了作为正在进行中的工作外,不宜引用本文档。
本文档由一个按照 W3C 专利 政策运作的组制作。 W3C 维护着一份 与该组交付成果相关的任何专利披露的公开列表; 该页面还包含 披露专利的说明。实际 知晓某项专利且认为该专利包含 必要权利要求的个人 必须按照 W3C 专利政策第 6 节 披露相关信息。
本文档受 2025年8月18日 W3C 流程文档管辖。
本节为非规范性内容。
LWS 协议定义了标准交互,某一方可通过这些交互向某些 代理提供某些资源。
资源管理者可以将被服务资源 保持为私有,可以使其对任何人公开可用,或者可以将其可见性限制到一组受约束的 请求代理。
除标记为非规范性的章节外,本规范中的所有创作指南、图表、示例和注释均为非规范性内容。 本规范中的其他所有内容均为规范性内容。
本文档中的关键词 MAY、MUST、MUST NOT、OPTIONAL、RECOMMENDED、REQUIRED、SHOULD 和 SHOULD NOT 应按 BCP 14 [RFC2119] [RFC8174] 中的描述解释,且仅当它们像这里所示以全 大写形式出现时才如此解释。
LWS 服务器是一个 HTTP 服务器 [rfc9112],它遵守 本规范中所有相关的“MUST”陈述。具体而言, 必须遵守本文档9. 操作中的相关规范性“MUST”陈述。
LWS 客户端是一个 HTTP 客户端 [rfc9112],它遵守本规范中所有相关的“MUST”陈述。具体而言,必须遵守本文档9. 操作中的相关规范性 “MUST”陈述。
术语“authorization server”和“client”由 OAuth 2.0 Authorization Framework [RFC6749] 定义。
术语“end-user”和“issuer”由 OpenID Connect Core 1.0 [OPENID-CONNECT-CORE] 定义。
本规范定义以下术语:
本节定义了一种机制,用于标识与链接式 Web 存储服务器交互的代理和最终用户。 本规范并不强制要求身份验证凭证采用特定 格式,但它确实描述了如何将现有身份系统 与链接式 Web 存储授权框架结合使用。
本节描述的数据模型概述了身份验证凭证的任何 具体序列化所需满足的要求。
身份验证凭证MUST 包含关于主体的防篡改声明,包括:
对身份验证凭证的验证需要凭证的 验证者和颁发者之间存在信任关系。此信任关系MAY 通过 带外机制建立。用于在验证者和颁发者之间建立信任的任何其他机制 均在特定的身份验证套件中概述。
身份验证凭证MUST 被签名。RECOMMENDED 使用非对称密码学 进行签名。
每个身份验证套件MUST 关联一个令牌类型 URI。身份验证套件SHOULD 使用 IANA “OAuth URI”注册表中定义的 URI。
存储描述资源提供 客户端在与存储交互时可使用的信息,包括能力和 服务端点的描述。
id - id 属性是REQUIRED。其值MUST 是一个 URI,用于
标识存储。
type - type 属性是REQUIRED。其值MUST 是一个字符串,
等于
Storage,或是一组字符串,其中包含等于 Storage 的项
(区分大小写)。
capability - capability 属性是OPTIONAL。其值MUST 是一组
能力,其中每个能力由包含以下属性的映射描述。
可以存在其他属性。
id - id 属性是OPTIONAL。如果存在,其值MUST
是一个 URI。type - type 属性是REQUIRED。其值MUST 是字符串
或一组字符串。service - service 属性是REQUIRED。其值MUST 是一组服务,
其中每个服务由包含以下属性的映射描述。可以存在其他
属性。
id - id 属性是OPTIONAL。如果存在,其值MUST
是一个 URI。type - type 属性是REQUIRED。其值MUST 是字符串
或一组字符串。serviceEndpoint - serviceEndpoint
属性是REQUIRED。其值MUST
是一个 URI。{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "https://storage.example/",
"type": "Storage",
"service": [{
"type": "StorageDescription",
"serviceEndpoint": "https://storage.example/description"
}]
}
所有针对存储资源的
GET 和 HEAD 请求的响应MUST 包含一个
Link 标头,其目标是存储
描述资源的 URI,并包含一个关系
(rel)参数,其值等于
https://www.w3.org/ns/lws#storageDescription。
解引用时,存储描述MUST 包含一个用于标识
存储的
id 属性。此外,service 属性MUST 包含一个服务描述,其类型等于
StorageDescription,并且其 serviceEndpoint 等于
存储描述的 URL。
除 StorageDescription 服务之外,存储描述资源可以包含
指向与存储相关联的其他服务的链接。这些服务的 API 定义不在
本规范范围内。
存储描述资源MUST 能够使用媒体类型
application/lws+json 序列化。
其他表示可以通过内容协商提供。
{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "https://storage.example/",
"type": "Storage",
"capability": [{
"type": "https://feature.example/PatchSupport",
"mediaType": {
"text/turtle": ["application/sparql-update"],
"application/n-triples": ["application/sparql-update"],
"application/linkset+json": ["application/merge-patch+json", "application/json-patch+json"]
}
}, {
"type": "https://feature.example/ResumableUploads"
}, {
"type": "https://feature.example/ContentNegotiation",
"source": "application/ld+json",
"target": ["text/turtle", "application/n-triples"]
}, {
"type": "https://feature.example/ContentNegotiation",
"source": "image/jpeg",
"target": ["image/png"]
}],
"service": [{
"type": "NotificationService",
"serviceEndpoint": "https://storage.example/notification/api",
"subscriptionType": ["WebhookSubscription"]
}, {
"type": "TypeIndexService",
"serviceEndpoint": "https://storage.example/types/index"
}, {
"type": "TypeSearchService",
"serviceEndpoint": "https://storage.example/types/search"
}, {
"type": "DataSharingService",
"serviceEndpoint": "https://storage.example/sharing/api"
}, {
"type": "StorageDescription",
"serviceEndpoint": "https://storage.example/description"
}]
}
Linked Web Storage 将资源组织到容器中。容器是一种 专门资源,它保存对其他资源的引用,这些资源称为其成员。容器充当 组织单元,类似于目录或集合,使客户端能够对资源进行分组、发现 和导航。容器维护对其成员资源的引用, 这些成员资源可以同时包括非容器资源和其他容器资源,从而支持 层级结构。通常,容器除了元数据或成员枚举之外, 仅包含最少的内在内容;其主要作用是聚合和结构化 下级资源。存储系统的根被指定为容器,作为 没有上级父项的顶层组织单元。容器MUST 使用 'ContainerPage' 类型支持成员列表的分页,并具有 'first'、 'next'、'prev' 和 'last' 等属性。表示MUST 使用带有特定 框架和规范性上下文的 JSON-LD,并可选择通过 'Vary: Accept' 标头宣告内容协商。 存储MAY 作为根容器运行,从而允许直接写入。
每个 LWS 存储都有一个存储 根,作为顶级组织单元。存储根没有父项,并充当 存储 层级的入口点。
LWS 中的资源被分类为以下两类之一:
资源与其父容器之间的包含关系通过 rel="up" 链接
关系表示。对于任何
非根资源上的 GET 和 HEAD 请求,服务器MUST 在响应中包含一个
Link 标头,其中 rel="up" 指向父容器。
Link: </alice/notes/>; rel="up"
容器的成员在其表示中使用
items 属性列出。服务器管理此列表;客户端不能直接修改它。成员关系
变更作为资源创建和删除的副作用发生。
服务器MUST 始终维护包含关系完整性:
资源由 URI 标识。资源的 URI 独立于其在包含关系层级中的位置。服务器在资源
创建期间分配 URI,并且MAY 纳入客户端提示(例如 Slug 标头),
但客户端SHOULD NOT 假定 URI 结构反映包含关系。
包含关系通过元数据表示
(rel="up" 链接和容器
表示中的 items 属性),而不是通过 URI 路径结构表示。这种分离允许服务器在 URI
分配方面具有灵活性,同时维护一个定义良好的组织模型。
当客户端检索容器时,服务器返回一个结构化的容器 表示,用于描述该容器及其内容。本节 定义容器表示的必需属性和可选属性。
容器表示MUST 包含以下属性:
items 数组中的每个条目描述容器中包含的一个资源。被包含资源描述MUST 包含:
id:被包含资源的 URI。type:资源的类型。MUST 是
"DataResource" 或 "Container",或是至少包含
这两个字符串之一的数组。服务器MAY 包含其他用户定义类型作为
URI(例如 ["DataResource", "http://example.org/customType"])。
被包含资源描述SHOULD 包含:
mediaType:资源的媒体类型(例如
"text/plain"、"image/jpeg")。对于 DataResources,
MUST 存在此项。
size:资源的大小,以字节为单位,以整数表示。
modified:资源最后修改的日期和时间,
表示为 ISO 8601 日期时间字符串。以下示例显示位于 /alice/notes/ 的一个容器,其中包含两个
资源:
{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "/alice/notes/",
"type": "Container",
"totalItems": 2,
"items": [
{
"type": "DataResource",
"id": "/alice/notes/shoppinglist.txt",
"mediaType": "text/plain",
"size": 47,
"modified": "2025-11-24T12:00:00Z"
},
{
"type": ["DataResource", "http://example.org/customType"],
"id": "/alice/notes/todo.json",
"mediaType": "application/json",
"size": 2048,
"modified": "2025-11-24T13:00:00Z"
}
]
}
本节定义 Linked Web Storage(LWS)服务器MUST 支持的四种核心操作。这些操作以 传输无关的方式操纵资源和容器,侧重于语义而不是实现细节。每个操作 都指定输入、预期行为和可能的响应。响应包括成功指示符、资源 表示(在适用时)和错误条件。实现MUST 以原子且一致的方式处理这些操作,这意味着每个操作要么完全成功,要么 失败且没有部分副作用。发生错误时,响应SHOULD 提供 足够细节,使代理能够理解问题,同时不泄露敏感信息。
对于每个核心操作(创建、读取、更新、删除),我们描述要使用的 HTTP 方法、所需 标头或特殊考量(包括通过 ETag 进行并发控制、内容协商,以及 容器列表的分页),以及服务器应执行和返回的内容。标准 HTTP 状态码 用于指示结果,并为诸如配额超出(507 Insufficient Storage)或前提条件失败(412 Precondition Failed)等场景提供额外映射。 该绑定尝试遵循 HTTP/1.1 和 相关 RFC(例如 [RFC7231] 用于 HTTP 语义,[RFC7233] 用于范围 请求,[RFC5789] 用于 PATCH,[RFC8288] 用于 Web Linking, 以及 [RFC9264] 用于 Link Sets),以便它自然地与 Web 标准集成。可发现性通过 诸如 401 响应上的 Link 标头和 WWW-Authenticate 标头等机制得到强调, 避免硬编码 URI 位置。各操作都要求元数据 集成,确保原子性,并使用 Link Sets 表示服务器管理和 用户管理的属性。
注:与本规范中的所有示例一样,本节给出的示例(HTTP 请求
和响应片段)均为非规范性,旨在说明典型用法。实际
要求在描述性文本和表格中陈述。此外,虽然此绑定涵盖 HTTP(作为
初始目标协议),但 LWS 操作原则上将来可以绑定到其他协议。
服务器MUST 对容器表示
支持 application/lws+json、
application/ld+json 和 application/json 的内容协商
(见11. LWS 媒体类型)。服务器MAY 另外支持 Turtle 等格式。
本节定义将元数据与LWS 资源相关联的模型。 LWS 元数据系统基于 Web Linking [RFC8288] 的原则,它 允许服务器使用带类型的链接描述资源之间的关系。元数据增强 可发现性,支持自描述 API,并与资源操作以及容器层级保持一致。
元数据模型 LWS 中的所有元数据都表示为一组源自某个资源(链接上下文)的带类型链接。 每个链接由以下部分组成:
元数据区分资源及其表示,从而在适用时允许多种媒体类型。 对于数据资源,元数据包括表示,每个表示都有 mediaType 和可选的 sizeInBytes。对于容器和数据资源,我们 将指向其父容器资源的链接视为该资源元数据的一部分。
Linkset 资源 对于存储中的每个资源,服务器MUST 按照 [RFC9264] 将元数据链接 作为独立资源提供。
rel="linkset" 的 Link 标头发现。
application/linkset+json 形式提供。发现元数据 客户端主要通过 GET 或 HEAD 请求响应中的 Link 标头来发现元数据。
rel="storageDescription" 的 Link 标头。
rel="up" 的
Link 标头,指向父容器。https://www.w3.org/ns/lws#PreferLinkRelations 来包含或省略特定关系。
元数据类型
| 类别 | 描述 |
|---|---|
| 系统管理 | 由服务器维护;只读。包括 linkset、type、
mediaType、size、modified。
|
| 核心元数据 | 由客户端管理(受服务器限制约束)。包括 up、
items、title、creator。
|
| 用户定义 | 由用户创建的自定义词汇表和索引。 |
可修改性考量 核心元数据MAY 由客户端修改。为确保互操作性,服务器 MUST 使用标准 HTTP 标头来宣告其能力:
方法发现:服务器MUST 通过 Allow 标头宣告对 linkset 资源上 GET 和 PATCH 操作的支持。
补丁格式发现:服务器MUST 通过 Accept-Patch 标头宣告
对 JSON Merge Patch [RFC7386] 的支持:
Accept-Patch: application/merge-patch+json。
可选方法:服务器MAY 支持 PUT 或替代补丁格式; 如果支持,则这些内容MUST 分别包含在 Allow 和 Accept-Patch 标头中。
[!IMPORTANT] 客户端SHOULD NOT 假定支持 PUT 或特定补丁格式, 除非它们在资源标头中被宣告,并且MUST 优雅处理 405 Method Not Allowed 或 415 Unsupported Media Type 响应。
管理元数据 元数据通过与资源关联的linkset 资源 URI 进行交互来管理。服务器MUST 支持更新的并发控制。
部分更新(PATCH):这是元数据管理的主要机制。服务器MUST 支持使用
application/merge-patch+json 的 PATCH。
替换(PUT):如果在 Allow 标头中宣告,客户端MAY 替换整个 linkset。如果服务器不支持 PUT,则它MUST 以 405 Method Not Allowed 拒绝该请求。
限制:服务器MAY 限制对特定链接(如
up 或 items)的修改,以维护系统完整性。
生命周期:元数据生命周期与所描述的资源绑定;删除资源MUST 导致自动移除其关联的linkset 资源元数据。
创建资源操作将一个新的被服务资源添加到现有容器中。此 操作同时处理数据资源和子容器的创建。
输入:
行为:
可能的响应:
新资源通过对目标容器 URI 使用 POST 创建,服务器分配
最终标识符。客户端MAY 通过 Slug 标头建议名称。
客户端MAY 通过在 POST 请求中
包含一个或多个 Link 标头,为新资源提供初始用户管理元数据,并遵循
[RFC8288]
中 Web Linking 的语法。服务器管理的元数据MUST
由服务器在创建时自动生成,并且MUST NOT 被
客户端提供的链接覆盖。
成功时,服务器MUST 返回 201 状态码,并在
Location 标头中包含新 URI。服务器MUST 包含 Link 标头,
用于关键服务器管理元数据,包括指向父容器的链接
(rel="up"),以及指向所创建资源的专用linkset 资源的链接
(rel="linkset"; type="application/linkset+json")。其他链接SHOULD 包括
rel="type"(表示
https://www.w3.org/ns/lws#Container 或
https://www.w3.org/ns/lws#DataResource)。正文MAY 为空或
包含资源的最小表示。所有元数据创建和链接MUST 与资源创建保持原子性,以维护一致性。
POST(到容器 URI) – 使用服务器分配的名称创建:
使用 POST 将新资源添加到现有容器内。服务器为该资源分配标识符,
可选择使用 Slug 标头提出建议。若 Slug 标头不与命名规则或现有
资源冲突,服务器MAY 采纳它。客户端按如下方式指示要创建的资源类型:
Link 标头,其 rel="type"
指向 Container 类型:
Link: <https://www.w3.org/ns/lws#Container>; rel="type"。
Content-Type 标头。示例(POST 创建新的数据资源):
POST /alice/notes/ HTTP/1.1
Host: example.com
Authorization: Bearer <token>
Content-Type: text/plain
Content-Length: 47
Slug: shoppinglist.txt
milk
eggs
bread
butter
apples
orange juice
在此示例中,客户端正在向容器 /alice/notes/ 发布。
它提供 text/plain 内容(一份购物清单),并建议使用
shoppinglist.txt 作为新资源的名称。如果 /alice/notes/ 存在且客户端
已获授权,服务器将创建一个新的数据资源,并将其添加到该容器的成员关系中。
示例(对 POST 的响应 — 数据资源):
HTTP/1.1 201 Created
Location: /alice/notes/shoppinglist.txt
Content-Type: text/plain; charset=UTF-8
Link: </alice/notes/shoppinglist.txt.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/notes/>; rel="up"
Link: <https://www.w3.org/ns/lws#DataResource>; rel="type"
Content-Length: 0
成功时,返回 201 Created,并在 Location 标头中包含新 URI。正文可以
为空或为最小表示。
如果目标容器 /alice/notes/ 不存在,则服务器
MUST 返回 404 错误状态,除非另一个状态码更合适。
创建容器:要创建新的容器,客户端对现有父容器使用 POST,并带有一个指示
Container 类型的 Link 标头。例如:
POST /alice/ HTTP/1.1
Host: example.com
Authorization: Bearer <token>
Content-Length: 0
Slug: notes
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
示例(对 POST 的响应 — 容器):
HTTP/1.1 201 Created
Location: /alice/notes/
Link: </alice/notes/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Content-Length: 0
这会在 /alice/notes/ 处创建一个新的容器,并带有服务器生成的
元数据,其中包括作为 https://www.w3.org/ns/lws#Container 的 rel="type"。
关于 Create(HTTP 绑定)的附加说明:
rel="storageDescription" 的 Link 标头,以便在没有硬编码 URI 的情况下引导客户端。
管理和检索元数据(与创建相关):
虽然元数据主要通过读取操作检索,但它会在创建期间生成。客户端可以
在创建后立即对新资源 URI 使用 GET 或 HEAD 检索它。客户端可以使用
Prefer 标头请求包含特定元数据链接(通过关系类型)和
属性。
检索现有资源的表示,或容器的列表。
读取资源操作通过 HTTP GET 请求(以及用于仅获取标头请求的 HEAD)
请求资源表示。行为取决于目标 URL 是容器还是非容器资源(数据资源)。服务器MUST
通过元数据区分资源类型。所有响应MUST 与
第 8.1 节定义的元数据集成,包括用于关键关系的 Link 标头,例如
rel="linkset"、rel="up" 和 rel="type"。服务器MUST 确保读取期间资源状态与其元数据之间的原子性。
GET(非容器资源) – 检索资源内容: 向资源 URI 发送 GET 以获取完整内容(如果已获授权)。以 200 OK 响应,正文包含 数据,Content-Type 与所存储的媒体类型匹配。服务器MUST 按照 [RFC7233] 支持 范围请求,以便部分检索。响应MUST 包含 ETag 标头,用于并发控制和 缓存。
示例(GET 一个文件):
GET /alice/notes/shoppinglist.txt HTTP/1.1
Authorization: Bearer <token>
Accept: text/plain
这会请求 /alice/notes/shoppinglist.txt 的内容,表明客户端希望
以文本形式获取它。假定资源存在、是文本,并且客户端有权访问:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 34
ETag: "abc123456"
Link: </alice/notes/shoppinglist.txt.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/notes/>; rel="up"
Link: <https://www.w3.org/ns/lws#DataResource>; rel="type"
milk
cheese
bread
guacamole
soda
chocolate bars
hash
eggs
服务器返回了文本内容(共 34 字节,如 Content-Length 所示)。
内容正是该文件中存储的数据。ETag: "abc123456" 是用于缓存或并发目的的版本
标识符。响应包含用于元数据
可发现性的 Link 标头,并带有 up 和 type 等强制字段。
GET(容器资源) – 列出容器内容: 当目标 URI 对应于容器(通过元数据类型确定)时,GET 请求返回该 容器成员的列表。响应正文是 容器表示,如容器表示一节所定义,使用 LWS 容器媒体 类型。该列表包括每个成员的元数据:资源标识符(MUST)、类型(MUST)、媒体类型(对于 DataResources,MUST)、大小(SHOULD)以及 修改时间戳(SHOULD)。
示例(GET 一个容器):
GET /alice/notes/ HTTP/1.1
Authorization: Bearer <token>
Accept: application/ld+json
假定容器存在且客户端有权访问:
HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "container-etag-789"
Link: </alice/notes/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "/alice/notes/",
"type": "Container",
"totalItems": 2,
"items": [
{
"type": "DataResource",
"id": "/alice/notes/shoppinglist.txt",
"mediaType": "text/plain",
"size": 47,
"modified": "2025-11-24T12:00:00Z"
},
{
"type": ["DataResource", "http://example.org/customType"],
"id": "/alice/notes/todo.json",
"mediaType": "application/json",
"size": 2048,
"modified": "2025-11-24T13:00:00Z"
}
]
}
在此示例中,/alice/notes/ 是一个容器。响应使用带有
LWS 上下文的 JSON-LD,列出带有必需元数据的成员。每个条目都包含其 type、
id、mediaType、size 和 modified 时间戳作为扁平
属性。
在所有情况下,服务器MUST 在响应
标头中包含以下元数据:ETag(表示列表版本,它会在成员关系修改时变化),以及
Link 标头,其中 rel="type" 表明它是一个容器,并包含 rel="linkset" 和
rel="up"。
HEAD(任何资源或容器) – 仅标头/元数据: LWS 服务器MUST 对容器和非容器均支持 HEAD [RFC9110], 返回与 GET 相同的标头(包括 ETag、Content-Type、用于元数据的 Link),但没有正文。这可以在不传输内容的情况下检索 元数据。
缓存和条件请求:LWS 利用 HTTP 缓存语义。服务器MUST 支持通过 If-None-Match(使用 ETag)或 If-Modified-Since 标头进行条件请求。如果资源或容器列表未更改,则响应 304 Not Modified,以避免冗余传输。所有 GET/HEAD 响应中MUST 提供 ETag, 用于并发和缓存支持。
可发现性和授权:为了增强可发现性,服务器SHOULD 在 401 Unauthorized 响应上包含带有 参数的 WWW-Authenticate 标头,以便在没有硬编码 URI 的情况下引导客户端。元数据链接SHOULD 在适用时包含。
通过完整替换或部分补丁修改现有 [served resource] 的状态。
更新资源通过 PUT 请求(替换整个资源)或 PATCH 请求(应用 部分修改)修改现有被服务 资源的内容。客户端必须对资源 URL 拥有写访问权限才能执行这些 操作。 注:本节描述更新资源的主要内容。要更新其元数据,请见第 9.3.2 节。 LWS 服务器MUST 将资源 URI 上的 PUT 和 PATCH 请求处理为 仅对资源内容的修改,默认情况下不影响关联的linkset 资源。为了可选择地在单个原子操作中同时更新内容和 元数据,客户端MAY 在对资源 URI 的 PUT/PATCH 请求中包含 Link 标头,并指定偏好 'Prefer: set-linkset'(如 RFC 7240 中所定义)。在这种情况下,服务器MUST 将提供的 Link 标头解释为 对 linkset 的替换(对于 PUT)或部分更新(对于 PATCH),并同时应用 内容更改。此行为对服务器而言是OPTIONAL,但如果支持,MUST 通过 Prefer 标头显式调用,以防止无意 覆盖元数据。不支持组合更新的服务器MUST 忽略 该偏好或以 501 Not Implemented 响应。
PUT(替换完整资源) – 向资源 URI 发送 PUT,并在
正文中包含新的完整内容和匹配的 Content-Type(通常与现有类型一致)。PUT 对现有
资源是幂等的。为安全起见,包含带有当前 ETag 的 If-Match(依据第 7.3 节并发);不匹配会产生
412 Precondition Failed 或 409 Conflict。如果没有检查,更新是无条件的,但可能覆盖
并发更改。如果服务器支持资源的 Etags,它MUST 以 428
Precondition Required 响应拒绝缺少 If-Match 标头的无条件 PUT 请求。
示例(PUT 更新资源):
PUT /alice/personalinfo.json HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
If-Match: "abc123456"
{
"name": "Alice",
"age": 30,
"city": "New London",
"state": "Connecticut"
}
在此示例中,客户端正在更新 /alice/personalinfo.json 处的现有 JSON 资源。它 包含一个 If-Match 标头,其中带有它从早先 GET 或 HEAD 请求获得的 ETag "abc123456"。 服务器会将其与当前 ETag 比较;如果匹配,就继续用 所提供的 JSON 替换内容。如果不匹配,服务器会拒绝更新(因为该资源在此期间 已被其他人更改)。 成功响应:如果更新成功,服务器可以用 200 OK 响应,并可能包含 更新后的表示或某些确认信息(例如新内容或其中一部分)。或者, 服务器可以用 204 No Content 响应,表示成功但无正文(如果无需传达更多 信息,这尤其常见)。无论哪种情况,服务器SHOULD 包含新的 ETag 来表示新版本,如果返回正文,也可以包含 Content-Type。例如:
HTTP/1.1 204 No Content
ETag: "def789012"
这会告诉客户端更新已完成,并提供新的 ETag。如果服务器选择
返回更新后的内容,它可能使用 200 OK 并在正文中包含 JSON,同时
带有标头。
If-Match 不匹配(并发
修改),服务器可以返回 412 Precondition Failed(表示
前提条件标头失败)或 409 Conflict —— 我们之前的抽象描述使用
Conflict 表示并发问题,而 409 是该场景的自然映射。如果资源
不存在,则旨在更新的 PUT 会导致 404 Not Found(除非意图是
创建,但通常客户端只有在确定自己正在做什么时才使用 PUT 创建,
或者将其作为没有 If-Match 的 upsert 使用)。如果客户端未获授权,
则为 403 Forbidden(或者在未提供有效凭据时为 401 Unauthorized)。如果
请求载荷无效,则为 400 Bad Request。
PATCH(部分更新) – HTTP PATCH 方法 [RFC5789] 允许客户端指定对资源的部分修改,而不是发送完整的新 内容。当资源很大且只有一小部分发生变化时,发送整个内容效率较低, 或者在并发编辑中希望应用特定更改时,这很有用。LWS 服务器MUST 至少支持 [RFC7386] 中定义的 JSON Merge Patch(application/merge-patch+json)。
更新资源元数据(对 Linkset 使用 HTTP PUT / PATCH) 资源的元数据通过修改其对应的linkset 资源来更新, 该资源通过带有 rel="linkset" 的 Link 标头发现。 完整替换(PUT):对linkset 资源 URI 发送 PUT 请求,并在正文中包含完整 linkset 文档,会替换该资源的所有元数据。 部分更新(PATCH):对linkset 资源 URI 发送 PATCH 请求,会添加、移除或 修改特定链接。
元数据的并发控制 因为资源的元数据可能由多个参与者修改,防止并发覆盖至关重要。 为确保数据完整性,LWS 服务器和客户端MUST 为所有 对linkset 资源的 PUT 和 PATCH 操作,实现使用条件请求 [RFC7232] 的乐观并发控制。 服务器职责: 服务器MUST 在其对linkset 资源的 GET 和 HEAD 请求响应中包含 Etag 标头。 在成功对 linkset 执行 PUT 或 PATCH 后,服务器MUST 为修改后的 linkset 生成新的、 唯一 Etag 值,并在响应的 Etag 标头中返回它。 客户端职责: 修改linkset 资源时,客户端MUST 包含一个 If-Match 标头,其中包含它最近收到的该资源 Etag。 处理规则: 如果 If-Match 标头值与 linkset 的当前 Etag 不匹配,服务器MUST 以 412 Precondition Failed 状态码拒绝请求。 如果对 linkset URI 的 PUT 或 PATCH 请求缺少 If-Match 标头,服务器MUST 以 428 Precondition Required 状态码拒绝请求 [RFC6585]。 示例(PUT 替换 linkset): 客户端首先获取 linkset 并接收其 ETag。
GET /alice/personalinfo.json.meta HTTP/1.1
Authorization: Bearer <token>
Accept: application/linkset+json
HTTP/1.1 200 OK
Content-Type: application/linkset+json
ETag: "meta-v1"
{
"linkset": [
{
"anchor": "/alice/personalinfo.json",
"describedby": [ { "href": "/schemas/personal-info.json" } ]
}
]
}
客户端现在想要添加许可证。它构造一个新的完整 linkset 文档,并发送带有 If-Match 标头的 PUT 请求。
PUT /alice/personalinfo.json.meta HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/linkset+json
If-Match: "meta-v1"
{
"linkset": [
{
"anchor": "/alice/personalinfo.json",
"describedby": [ { "href": "/schemas/personal-info.json" } ],
"license": [ { "href": "https://creativecommons.org/licenses/by/4.0/" } ]
}
]
}
如果成功,服务器以成功响应,并返回新的 ETag。
HTTP/1.1 204 No Content
ETag: "meta-v2"
更新规则摘要 如果你只想更改资源的内容 → 对资源本身执行 PUT/PATCH。 如果你只想更改资源的链接(元数据)→ 对该资源关联的linkset 资源执行 PUT/PATCH。 如果你想同时更改内容和链接 → 对资源本身执行 PUT/PATCH,并包含适当的 Link 标头和 'Prefer: set-linkset'。同时设置默认关闭。
永久移除资源及其关联元数据。
删除资源操作使用 HTTP DELETE 方法实现,如上述抽象 操作中所定义。本节指定输入、行为和响应的 HTTP 绑定。
DELETE 请求以要移除的资源或容器的 URI 为目标。客户端MAY 包含带有 ETag 的
If-Match 标头,以进行并发
检查。
删除和包含关系:
删除资源时,服务器MUST 以原子方式将其从其
父容器的 items 列表中移除。父容器的
totalItems 计数SHOULD 相应更新,并且其 ETagMUST
被更新以反映该变更。
对于非容器资源,服务器移除资源内容、其关联元数据(linkset 资源),以及父容器中的包含关系引用。
对于容器资源,服务器默认执行非递归
删除。如果该容器非空且未请求递归,则服务器
MUST 以 409 Conflict 拒绝请求。服务器MAY
支持递归删除正在被删除的容器内的所有包含资源。
客户端MUST 使用 Depth: infinity 标头来请求
递归删除,如 [RFC4918] 中所定义。
成功时,服务器MUST 以 204 No Content 响应。服务器SHOULD 支持条件请求,如 [RFC9110] 中所定义。
如果客户端缺少授权,服务器MUST 返回 403 Forbidden(如果 客户端身份已知但权限不足)或 401 Unauthorized(如果未提供有效 身份验证)。在泄露资源存在性会造成安全风险的情况下, 服务器MAY 改为返回 404 Not Found。
示例(DELETE 非容器资源):
DELETE /alice/notes/shoppinglist.txt HTTP/1.1
Authorization: Bearer <token>
If-Match: "abc123456"
假定 ETag 匹配且客户端已获授权,服务器会以原子方式删除资源、其元数据,
并将其从父容器 /alice/notes/ 中移除:
HTTP/1.1 204 No Content
示例(DELETE 非空容器且不递归):
DELETE /alice/notes/ HTTP/1.1
Authorization: Bearer <token>
假定 /alice/notes/ 包含资源,服务器会拒绝删除:
HTTP/1.1 409 Conflict
Content-Type: text/plain
Cannot delete container /alice/notes/ - container is not empty.
示例(如果支持,递归 DELETE 容器):
DELETE /alice/notes/ HTTP/1.1
Authorization: Bearer <token>
Depth: infinity
假定服务器支持递归且客户端对所有内容都有权限,服务器会以原子方式 删除该容器及其后代:
HTTP/1.1 204 No Content
此表将通用 LWS 响应(来自 第 8 节)映射到 HTTP 状态码和载荷,以保持一致性,并纳入诸如 分页、并发控制、配额约束和元数据集成等特定场景:
| LWS 响应 | HTTP 状态码 | HTTP 载荷 |
|---|---|---|
| 成功(读取或更新,返回 数据) | 200 OK | 响应正文中的资源 表示(用于 GET,或在 PUT/PATCH 返回内容时),以及 相关标头(Content-Type、ETag、用于元数据的 Link,例如 rel="linkset"、 rel="up")。对于容器列表,包含带有规范性上下文和成员 元数据(ID、类型、大小、时间戳)的 JSON-LD。 |
| 已创建(新资源) | 201 Created | 通常没有响应正文(或新资源的最小表示)。
Location 标头设置为新资源的 URI。用于并发的 ETag 等标头MUST
被包含;还包括用于服务器管理
元数据的 Link 标头。
|
| 已删除(没有内容可返回) | 204 No Content | 无响应正文。表示资源已被删除,或请求成功且没有 其他内容可说。服务器MAY 对永久 删除使用 410 Gone。 |
| 错误请求(输入或约束无效) | 400 Bad Request | 解释错误所在的错误详情。服务器SHOULD 使用 [RFC9457] 中定义的 标准格式来提供结构化错误响应,例如带有 "type"、"title"、 "status"、"detail" 和 "instance" 等字段的 JSON 对象。 |
访问请求和授予提供一种机制,使代理能够请求访问 资源,并使存储控制者能够在定义的约束下授予访问权限。 用于请求和授予访问权限的端点充当一种专用收件箱。
代理不会 将访问授予作为授权令牌呈现给服务器。 相反,访问授予作为一条记录,记录授权了什么、授予给谁、 以及在什么约束下授权。当访问授予被创建或撤销(删除)时, 服务器有责任调整任何底层访问策略,以反映该 变更。访问授予端点与特定策略 执行层之间的交互不在本规范范围内。
本节中定义的访问配置文件基于 开放数字版权语言(ODRL)中的概念,包括 动作、约束和被指派方。其他配置文件可以使用不同的概念框架。
存储MAY 在其存储描述资源中宣告对访问请求和
访问授予的支持。当宣告此类支持时,描述
访问请求端点的服务
对象MUST 具有等于字符串 AccessRequestService 的
type,并且描述访问授予端点的服务对象MUST
具有
等于字符串 AccessGrantService 的 type。服务
对象SHOULD 包含一个 conformsTo 属性,其值为一个
由一个或多个 URI 组成的集合,用于标识该端点支持的访问配置文件。
可以包含其他属性:
{
"@context": [
"https://www.w3.org/ns/lws/v1"
],
"id": "https://storage.example/",
"type": "Storage",
"service": [
{
"type": "AccessRequestService",
"serviceEndpoint": "https://access.example/request/",
"conformsTo": ["https://www.w3.org/ns/lws#AccessProfile"]
},
{
"type": "AccessGrantService",
"serviceEndpoint": "https://access.example/grant/",
"conformsTo": ["https://www.w3.org/ns/lws#AccessProfile"]
}
]
}
访问请求或访问授予是一个数据
对象,用于表达身份和路由相关的属性,以及一个描述所
请求或许可操作的 access 对象。一个使用
ODRL 概念描述访问请求的配置文件
在10.3
访问配置文件中描述。
以下示例展示一个访问请求。该示例 使用10.4.1 JSON-LD 序列化中定义的 JSON-LD 序列化显示。
{
"@context": [
"https://www.w3.org/ns/lws/v1"
],
"type": ["AccessRequest"],
"inbox": "https://id.example/agent/inbox/",
"storage": "https://storage.example/",
"access": [{
"type": ["AccessPolicy"],
"action": ["read", "create"],
"assignee": "https://id.example/agent",
"target": {
"type": "StorageResource",
"value": ["https://storage.example/projects/"]
},
"constraint": [
{
"leftOperand": "purpose",
"operator": "eq",
"rightOperand": "https://purpose.example/collaboration"
},
{
"leftOperand": "dateTime",
"operator": "lteq",
"rightOperand": "2026-06-09T10:00:00Z"
}
]
}]
}
以下示例展示一个访问授予。该示例 使用10.4.1 JSON-LD 序列化中定义的 JSON-LD 序列化显示。
{
"@context": [
"https://www.w3.org/ns/lws/v1"
],
"type": ["AccessGrant"],
"storage": "https://storage.example/",
"access": [{
"type": ["AccessPolicy"],
"action": ["read"],
"assignee": "https://id.example/agent",
"target": {
"type": "StorageResource",
"value": ["https://storage.example/projects/"]
},
"constraint": [
{
"leftOperand": "purpose",
"operator": "eq",
"rightOperand": "https://purpose.example/collaboration"
},
{
"leftOperand": "dateTime",
"operator": "lteq",
"rightOperand": "2026-06-09T10:00:00Z"
}
]
}]
}
type 属性表达文档的类型。
type 属性的值MUST 是一个或多个
术语和
绝对 URL 字符串。对于
访问请求,该值MUST
包含术语 AccessRequest。
对于访问授予,该值MUST
包含术语
AccessGrant。可以包含其他类型值。
此属性是REQUIRED。
{
"type": ["AccessGrant"]
}
storage 属性标识
访问请求或访问授予所限定到的 LWS 存储。
storage 属性的值MUST 是 URI。
此属性是REQUIRED。
{
"storage": "https://storage.example/"
}
inbox 属性指定一个 URI,用于接收与
访问请求或访问授予
相关的通知
(见10.6
通知)。
inbox 属性的值MUST 是 URI。
此属性是OPTIONAL。
{
"inbox": "https://id.example/agent/inbox/"
}
access 属性基于服务器支持的配置文件,描述一个或多个
访问配置文件的特征。一个基于
ODRL 信息模型的
配置文件在10.3 访问配置文件中描述。
access 属性的值MUST 是一个由一个或多个
对象组成的集合。
此属性是REQUIRED。
本规范定义一个基于
ODRL
信息模型和ODRL
词汇表的访问配置文件,并用以下 URL 标识:
https://www.w3.org/ns/lws#AccessProfile。
type 属性表达访问策略的类型。
type 属性的值MUST 是一个或多个
术语和
绝对 URL 字符串,并且MUST 包含
术语 AccessPolicy。可以包含其他类型值。
该属性是REQUIRED。
{
"access": [{
"type": ["AccessPolicy"]
}]
}
action 属性描述代理希望执行
(在请求的情况下)或被授权执行(在授予的情况下)的
操作。
action 属性的值MUST 是一个由一个或多个
字符串组成的集合。每个值MUST 对应服务器识别的操作。
必须支持以下值:read、modify、
create 和 delete。read、
modify 和 delete 值由
ODRL
词汇表定义。
create 值由本
规范定义。
这些动作值与 LWS 操作的对应关系如下:
read — 检索资源或其元数据(HTTP GET、HEAD)modify — 修改现有资源(HTTP PUT、PATCH)create — 在容器内创建新资源(HTTP POST)
delete — 移除现有资源(HTTP DELETE)此属性是REQUIRED。
{
"access": [{
"action": ["read", "create"]
}]
}
assignee 属性标识请求访问的一方(在
请求的情况下)或被授予访问权限的一方(在授予的情况下)。
assignee 属性的值MUST 是 URI。公共
访问MAY 使用来自FOAF
词汇表的 Agent 类来
指派,其 URI 为
http://xmlns.com/foaf/0.1/Agent。
此属性是REQUIRED。
{
"access": [{
"assignee": "https://id.example/agent"
}]
}
target 属性MUST 是包含以下属性的对象:
type — 标识
目标匹配器类型的术语或
绝对 URL 字符串。
value — 用于标识
目标资源的一个或多个字符串组成的集合。
本规范定义以下 type 值以供
目标对象使用:
https://www.w3.org/ns/lws#DataResource — 匹配
类型为 lws:DataResource 的资源。
https://www.w3.org/ns/lws#Container — 匹配
类型为 lws:Container 的资源。
https://www.w3.org/ns/lws#StorageResource — 匹配
由存储管理的任何资源。
服务器MAY 支持其他类型值。
此属性是OPTIONAL。
{
"access": [{
"target": {
"type": "StorageResource",
"value": [
"https://storage.example/data/2025",
"https://storage.example/data/2026"
]
}
}]
}
constraint 属性定义限制或限定所
请求或授予的访问的条件。此属性使用 ODRL
约束模型。
如果存在,constraint 属性的值MUST 是一个
约束对象集合。每个约束对象MUST 包含以下
属性:
leftOperand — 标识被约束操作数的字符串。
operator — 标识比较运算符的字符串。
rightOperand — 要比较的值。其类型取决于
leftOperand。
当存在多个约束对象时,所有这些约束对象都MUST 被 满足。
宣告支持此配置文件的服务器MUST 支持以下
leftOperand 值:
client — 表示 HTTP 请求的客户端标识符
mediaType — 表示目标 HTTP
资源的媒体类型
type — 表示资源链接
标头中表达的类型 URL
purpose — 表示所
请求或授予访问的预期用途
dateTime — 表示当前日期时间
此属性是OPTIONAL。
以下示例展示这些约束的使用:
以下示例使用
purpose 作为 leftOperand 值,来描述所
请求或授予访问的预期
用途。当使用 eq 运算符时,
rightOperand 值是标识目的的 URI。
当使用 isAnyOf 运算符时,rightOperand
值是目的 URI 数组,并且如果所声明的目的与列出值中的任一项匹配,
则满足约束:
{
"access": [{
"constraint": [
{
"leftOperand": "purpose",
"operator": "isAnyOf",
"rightOperand": [
"https://purpose.example/collaboration",
"https://purpose.example/research"
]
}
]
}]
}
以下示例使用
client 作为 leftOperand 值,将访问限制
到特定客户端应用程序。当使用 eq 运算符时,
rightOperand 值是标识客户端的 URI:
{
"access": [{
"constraint": [
{
"leftOperand": "client",
"operator": "eq",
"rightOperand": "https://app.example/client-id"
}
]
}]
}
以下示例使用
mediaType 作为 leftOperand 值,将
访问限制到具有特定媒体类型的资源。当使用 eq 运算符
时,rightOperand 值是标识
IANA 媒体类型的字符串。当
使用 isAnyOf 运算符时,rightOperand 值
是媒体类型字符串数组,并且如果资源的
媒体类型与列出值中的任一项匹配,则允许访问:
{
"access": [{
"constraint": [
{
"leftOperand": "mediaType",
"operator": "isAnyOf",
"rightOperand": ["image/jpeg", "image/png"]
}
]
}]
}
所有 LWS 资源都将包含指示类型值的链接标头:
Link: <https://www.w3.org/ns/lws#DataResource>; rel="type"
Link: <https://type.example/Playlist>; rel="type"
以下示例使用
type 作为 leftOperand 值,基于 HTTP Link 标头中
宣告的资源类型来限制访问。
当使用 eq 运算符时,rightOperand 值
是标识资源类型的 URI。当使用 isAnyOf 运算符时,
rightOperand 值是类型 URI 数组,并且如果
资源的类型与列出值中的任一项匹配,则允许访问:
{
"access": [{
"constraint": [
{
"leftOperand": "type",
"operator": "isAnyOf",
"rightOperand": [
"https://type.example/Playlist",
"https://type.example/Song"
]
}
]
}]
}
以下示例使用
dateTime 作为 leftOperand 值,将访问限制
到特定时间窗口。gteq 运算符定义
窗口的开始,而 lteq 运算符定义结束。
时间约束的 rightOperand 值是
XML
Schema dateTime 字符串:
{
"access": [{
"constraint": [
{
"leftOperand": "dateTime",
"operator": "gteq",
"rightOperand": "2026-03-09T12:00:00Z"
},
{
"leftOperand": "dateTime",
"operator": "lteq",
"rightOperand": "2026-06-09T10:00:00Z"
}
]
}]
}
当存在多个约束对象时,所有这些约束对象都MUST 被满足, 才允许访问。以下示例将访问限制为特定客户端 应用程序,并要求在特定日期之前:
{
"access": [{
"action": ["read"],
"assignee": "https://id.example/agent",
"target": {
"type": "StorageResource",
"value": ["https://storage.example/projects/"]
},
"constraint": [
{
"leftOperand": "dateTime",
"operator": "lteq",
"rightOperand": "2026-06-09T10:00:00Z"
},
{
"leftOperand": "client",
"operator": "eq",
"rightOperand": "https://app.example/client-id"
}
]
}]
}
本节中定义的数据模型独立于任何特定的 序列化。
本规范为访问请求
和
访问授予定义 JSON-LD 序列化。使用此序列化的文档MUST
包含
@context 属性,其值是一个有序集合,并包含
https://www.w3.org/ns/lws/v1。可以
包含其他上下文条目以定义扩展术语。
与此序列化关联的媒体类型是 application/lws+json。
{
"@context": [
"https://www.w3.org/ns/lws/v1"
]
}
访问请求和访问授予端点 是 LWS 容器,并且MUST 符合本规范中定义的规则。
这些端点至少需要支持 GET 和 POST 操作。DELETE 操作 是RECOMMENDED。其他操作MAY 受支持。
这些端点MUST 支持 10.4.1 JSON-LD 序列化中定义的 JSON-LD 序列化,用于请求和响应载荷。服务器 MAY 支持其他序列化。
代理
通过向
访问请求端点提交 POST 请求来
创建访问请求。
存储
控制者通过
向访问授予端点提交 POST 请求
创建访问授予。
成功的 POST 操作MUST 以设置为
新资源 URL 的 Location 标头进行响应。
POST / — 创建访问请求。GET / — 检索访问请求列表。GET /:id — 检索特定访问请求。DELETE /:id — 取消访问请求。POST / — 创建访问授予。GET / — 检索访问授予列表。GET /:id — 检索特定访问授予。DELETE /:id — 撤销访问授予。
通知提供一种机制,用于告知代理和存储
控制者有关
访问请求和访问授予的变更。当
访问请求或访问授予上存在
inbox 属性时,
服务器SHOULD 向该端点传递
通知,告知被指派方该事件。
通知的序列化MUST 符合 LWS 通知数据模型的要求。
传递到 inbox 端点的通知MUST 符合
LWS 协议中为通知传递定义的要求。
本节中描述的通知机制可与
Linked Data Notifications 模式相比,在该模式中
通知通过 inbox 属性发现,并通过向该 inbox 发送 POST
请求进行传递。
服务器SHOULD 响应以下事件发送通知:
服务器MAY 响应其他事件发送通知。
LWS 容器表示和存储描述资源MUST 使用媒体类型
application/lws+json。
虽然 LWS 容器表示使用 JSON-LD 约定,但 LWS 的约束和要求
使得使用特定媒体类型是合理的。因为 LWS 容器可被视为 JSON-LD 的受限配置文件,
实现SHOULD 将
application/ld+json; profile="https://www.w3.org/ns/lws/v1" 媒体类型视为等同于
application/lws+json。
服务器MUST 支持容器表示的内容协商。
无论请求的媒体类型是什么,响应载荷MUST 相同 —
只有 Content-Type 响应标头会变化:
application/lws+json,服务器MUST
以 Content-Type: application/lws+json 响应。application/ld+json,服务器MUST
以 Content-Type: application/ld+json 响应。application/json,服务器MUST
以 Content-Type: application/json 响应。在这三种情况下,响应正文都是符合 LWS 容器
词汇表的同一个 JSON-LD 文档。服务器可以通过内容协商自由支持其他媒体类型
(例如 text/turtle)。
某些复合资源,例如容器,可能包含大量资源。 为了允许客户端逐步检索列表,服务器SHOULD 对成员数量超过 服务器确定阈值的容器支持 分页。
分页基于链接:服务器通过 HTTP Link 标头提供分页 URI
[RFC8288],
允许客户端在不依赖数字偏移量的情况下导航完整列表。
当列表被分页时,响应正文仅包含当前页的条目。复合资源的
id、type 和 totalItems 属性
反映完整成员关系,而 items
仅包含当前页上的资源。
分页 URI 使用以下标准链接
关系在 Link 标头中传达:
rel="first":结果第一页的 URI。MUST 出现在分页响应中。
rel="last":结果最后一页的 URI。MAY 出现在分页响应中。
rel="next":结果下一页的 URI。当存在后续
页面时MUST 出现。在最后一页上MUST 省略。rel="prev":结果上一页的 URI。当存在前置
页面时MAY 出现。在第一页上MUST 省略。所有分页 URI 对客户端都是不透明的。客户端SHOULD NOT 构造或修改分页 URI;它们SHOULD 使用服务器提供的 URI。
客户端请求复合资源的 URI 以获得第一页。响应包含 分页 Link 标头,客户端可跟随这些标头检索后续页面。服务器MAY 也支持 通过先前扫描期间获得的分页 URI 直接访问特定页面。
当返回分页响应时,服务器MUST 以 200
OK 响应。响应正文中的 totalItems
属性SHOULD 反映所有页面中的条目总数,
而不仅仅是当前页。
请求:
GET /alice/photos/ HTTP/1.1
Authorization: Bearer <token>
Accept: application/lws+json
响应(第一页):
HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "photos-page1-etag"
Link: </alice/photos/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: </alice/photos/.acl>; rel="acl"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Link: </alice/photos/?page=1>; rel="first"
Link: </alice/photos/?page=3>; rel="last"
Link: </alice/photos/?page=2>; rel="next"
{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "/alice/photos/",
"type": "Container",
"totalItems": 150,
"items": [
{
"type": "DataResource",
"id": "/alice/photos/vacation.jpg",
"mediaType": "image/jpeg",
"size": 248392,
"modified": "2025-11-20T10:30:00Z"
},
{
"type": "DataResource",
"id": "/alice/photos/portrait.png",
"mediaType": "image/png",
"size": 102400,
"modified": "2025-11-21T14:15:00Z"
}
]
}
请求(下一页):
GET /alice/photos/?page=2 HTTP/1.1
Authorization: Bearer <token>
Accept: application/lws+json
响应(中间页):
HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "photos-page2-etag"
Link: </alice/photos/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: </alice/photos/.acl>; rel="acl"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Link: </alice/photos/?page=1>; rel="first"
Link: </alice/photos/?page=1>; rel="prev"
Link: </alice/photos/?page=3>; rel="next"
Link: </alice/photos/?page=3>; rel="last"
{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "/alice/photos/",
"type": "Container",
"totalItems": 150,
"items": [
{
"type": "DataResource",
"id": "/alice/photos/sunset.jpg",
"mediaType": "image/jpeg",
"size": 315000,
"modified": "2025-11-22T09:00:00Z"
}
]
}
容器表示MUST 包含以下 @context
值:
"@context": "https://www.w3.org/ns/lws/v1"
规范性 JSON-LD 上下文文档定义了 容器表示中使用的短属性名与其在 LWS 和 相关词汇表中的完整 URI 之间的映射。上下文定义如下:
{
"@context": {
"@version": 1.1,
"@protected": true,
"lws": "https://www.w3.org/ns/lws#",
"as": "https://www.w3.org/ns/activitystreams#",
"schema": "https://schema.org/",
"xs": "http://www.w3.org/2001/XMLSchema#",
"id": "@id",
"type": "@type",
"Container": "lws:Container",
"DataResource": "lws:DataResource",
"items": "lws:items",
"totalItems": "as:totalItems",
"mediaType": "as:mediaType",
"size": {
"@id": "schema:size",
"@type": "xs:long"
},
"modified": {
"@id": "as:updated",
"@type": "xs:dateTime"
}
}
}
该上下文是 @protected 的,确保术语定义不能被
其他上下文覆盖。
LWS 词汇表定义了容器 表示中使用的以下类型和属性:
类型:
| 术语 | URI | 描述 |
|---|---|---|
Container |
lws:Container |
包含其他资源的资源 |
DataResource |
lws:DataResource |
承载数据的资源 |
属性:
| 术语 | URI | 描述 |
|---|---|---|
items |
lws:items |
容器中包含的资源列表 |
totalItems |
as:totalItems |
被包含资源的总数 |
mediaType |
as:mediaType |
资源的媒体类型 |
size |
schema:size |
资源大小,以字节为单位 |
modified |
as:updated |
资源最后修改的日期时间 |
定义在 LWS Protocol 中如何标识和寻址资源,包括 URI 方案、资源命名约定和解析机制。本节可能会被移至 另一节;例如 Resource Access
此处有意留空
描述用于确保 LWS 实现能够跨不同 平台、环境和存储后端工作并保持互操作性的考量,并提供 可供性能力以支持更换存储提供者
此处有意留空
本节为非规范性内容。
正式的安全考量章节,涵盖威胁模型、安全要求,以及 安全 LWS 部署的实现指南。
OAuth 2.0 Security 当前最佳实践 [RFC9700] 中描述的建议适用于本 规范。
本节为非规范性内容。
传输层安全性(TLS)是防止篡改、仿冒和 信息泄露的重要机制。受 TLS 保护的通信可按照 [RFC6125] 进行验证。 实现安全考量可见“传输层安全性(TLS)和数据报传输层安全性(DTLS)的安全使用建议” [RFC9325]。
本节为非规范性内容。
Bearer 令牌和数字凭证容易遭受盗窃和重放。缓解措施包括使用 合理较短的生命周期、将令牌绑定到特定受众,以及安全存储令牌。
aud 声明等方式绑定到特定目标服务器的访问令牌,
可以依赖该绑定来防止令牌重放。处理不受限制受众的凭证的应用程序
在将这些凭证发送给其他实体时需要谨慎,尤其是不受信任的授权服务器。
如果凭证颁发者无法限制令牌的受众,客户端可以使用 OAuth 2.0 Token
Exchange [RFC8693] 等机制,
在与不同安全域中的授权服务器交互之前创建受众受限的
凭证。
localStorage 中、URL 中
或日志中,该令牌就更容易受到数据外泄攻击。
本节为非规范性内容。
本节为非规范性内容。
LWS Protocol 的隐私影响,包括数据最小化、用户同意,以及 保护隐私的实现模式。
凭证携带关于用户和代理的信息。虽然数字签名可以防止篡改, 但客户端或第三方仍可能读取未加密凭证内部的值。
因此,鼓励凭证颁发者创建仅包含身份验证或授权所必需信息的令牌, 并避免包含敏感属性,除非确有需要。
一般来说,将未加密凭证数据写入日志是一种反模式。在确有必要的情况下, 实现可以截断或哈希凭证,以保护凭证主体的隐私。
在 JWT 中使用假名标识符时,存储服务器仍可能能够随时间关联来自 同一代理的请求。 为在这种情况下保护用户隐私,客户端应用程序可以请求批量颁发 JWT,其中每个 JWT 只使用一次。 这不能防止存储服务器使用其他信息(例如 JWT 内容相似性或 来源 IP 地址)来关联请求。使用假名标识符时,授权服务器需要谨慎, 不要多次颁发相同标识符。
本节为非规范性内容。
本节为非规范性内容。
本规范将以下值添加到由 RFC 5785 [RFC5785] 建立的“Well-Known URIs”注册表。
本规范专门注册 application/lws+json 媒体类型,用于
标识符合 Linked Web Storage 容器格式的文档。
application/lws+json 媒体类型的资源
需要符合
application/json 媒体类型的所有要求,因此受
[RFC8259] 第 11 节中规定的相同编码
考量约束。
注意,虽然 Linked Web Storage 格式使用 JSON-LD 约定,但 LWS 实现还有若干 约束和附加 要求,使得使用特定媒体类型是合理的。
因为 LWS 容器可被视为 JSON-LD 的受限配置文件,实现SHOULD 将
application/ld+json; profile="https://www.w3.org/ns/lws/v1" 媒体类型视为等同于
application/lws+json。
本节为非规范性内容。
本规范大量借鉴了 Solid Protocol [Solid-Protocol],该协议由 Sarven Capadisli、Tim Berners-Lee、Kjetil Kjernsmo、Ruben Verborgh、Justin Bingham、Dmitri Zagidulin 随时间推移编辑而成。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: