http 请求系列
http request-01-XMLHttpRequest XHR 简单介绍
http request-01-XMLHttpRequest XHR 标准
Ajax 详解-01-AJAX(Asynchronous JavaScript and XML)入门介绍
Ajax XHR 的替代方案-fetch
Ajax XHR 的替代方案-fetch 标准
Ajax 的替代方案-axios.js
http 请求-04-promise 对象 + async/await
1. 前言
从高层次来看,获取资源是一个相当简单的操作。请求发出,响应返回。然而,这一操作的细节相当复杂,过去通常没有被仔细记录,并且在不同的 API 之间有所不同。
许多 API 提供了获取资源的能力,例如 HTML 的 <img>
和 <script>
元素,CSS 的 cursor
和 list-style-image
,JavaScript 的 navigator.sendBeacon()
和 self.importScripts()
API。Fetch 标准提供了一个统一的架构,使这些功能在各种获取方面(如重定向和 CORS 协议)保持一致。
Fetch 标准还定义了 fetch()
JavaScript API,该 API 在相对较低的抽象层次上暴露了大部分网络功能。
2. 基础设施
本规范依赖于 Infra 标准。[INFRA]
本规范使用了来自 ABNF、编码、HTML、HTTP、MIME 检测、Streams、URL、Web IDL 和 WebSockets 的术语。[ABNF] [ENCODING] [HTML] [HTTP] [MIMESNIFF] [STREAMS] [URL] [WEBIDL] [WEBSOCKETS]
ABNF 指的是由 HTTP(特别是添加了 # 的部分)和 RFC 7405 扩展的 ABNF。[RFC7405]
凭证是 HTTP cookies、TLS 客户端证书和认证条目(用于 HTTP 认证)。[COOKIES] [TLS] [HTTP]
fetch params
是一个用于 fetch
算法的簿记细节的结构体。它包含以下项目:
request
:一个请求。process request body chunk length
(默认值为 null):处理请求体块长度。process request end-of-body
(默认值为 null):处理请求体结束。process early hints response
(默认值为 null):处理早期提示响应。process response
(默认值为 null):处理响应。process response end-of-body
(默认值为 null):处理响应体结束。process response consume body
(默认值为 null):处理响应体消费。task destination
(默认值为 null):目标,可能是 null、全局对象或并行队列。cross-origin isolated capability
(默认值为 false):跨源隔离能力,布尔值。controller
(默认值为新建的 fetch controller):一个 fetch 控制器。timing info
:一个 fetch 时间信息。preloaded response candidate
(默认值为 null):预加载的响应候选项,可能是 null、"pending" 或响应。
fetch controller
是一个结构体,用于使 fetch
的调用者在开始之后对其执行某些操作。它包含以下项目:
state
(默认值为 "ongoing"):状态,可能是 "ongoing"、"terminated" 或 "aborted"。full timing info
(默认值为 null):完整时间信息,可能是 null 或 fetch 时间信息。report timing steps
(默认值为 null):报告时间步骤,可能是 null 或接受全局对象的算法。serialized abort reason
(默认值为 null):序列化的中止原因,可能是 null 或结构化序列化的记录。next manual redirect steps
(默认值为 null):下一步手动重定向步骤,可能是 null 或不接受任何内容的算法。
要报告给定全局对象的 fetch 控制器的时间:
- 断言:控制器的报告时间步骤不能为空。
- 调用控制器的报告时间步骤,传入全局对象。
要处理 fetch 控制器的下一个手动重定向:
- 断言:控制器的下一个手动重定向步骤不能为空。
- 调用控制器的下一个手动重定向步骤。
要提取 fetch 控制器的完整时间信息:
- 断言:控制器的完整时间信息不能为空。
- 返回控制器的完整时间信息。
要中止 fetch 控制器(可选地传递错误):
- 将控制器的状态设置为 "aborted"。
- 如果没有给定错误,设置 fallbackError 为 "AbortError" DOMException。
- 将错误设置为 fallbackError(如果没有给定错误)。
- 将序列化错误设置为 StructuredSerialize(error)。如果抛出异常,捕获它,并将序列化错误设置为 StructuredSerialize(fallbackError)。
- 将控制器的序列化中止原因设置为序列化错误。
要反序列化序列化的中止原因,给定 null 或记录 abortReason 和领域 realm:
- 设 fallbackError 为 "AbortError" DOMException。
- 将 deserializedError 设为 fallbackError。
- 如果 abortReason 不为 null,则将 deserializedError 设置为 StructuredDeserialize(abortReason, realm)。如果抛出异常或返回 undefined,则将 deserializedError 设置为 fallbackError。
- 返回 deserializedError。
要终止 fetch 控制器,将控制器的状态设置为 "terminated"。
如果 fetch 参数的控制器状态为 "aborted",则该 fetch 参数被中止。
如果 fetch 参数的控制器状态为 "aborted" 或 "terminated",则该 fetch 参数被取消。
fetch timing info
是一个结构体,用于维护 Resource Timing 和 Navigation Timing 所需的时间信息。它包含以下项目:[RESOURCE-TIMING] [NAVIGATION-TIMING]
start time
(默认值为 0):开始时间。redirect start time
(默认值为 0):重定向开始时间。redirect end time
(默认值为 0):重定向结束时间。post-redirect start time
(默认值为 0):重定向后的开始时间。final service worker start time
(默认值为 0):最终服务工作者开始时间。final network-request start time
(默认值为 0):最终网络请求开始时间。first interim network-response start time
(默认值为 0):首次中间网络响应开始时间。final network-response start time
(默认值为 0):最终网络响应开始时间。end time
(默认值为 0):结束时间。
final connection timing info
(默认值为 null):最终连接时间信息,可能为 null 或连接时间信息。
server-timing headers
(默认值为 « »):服务器时间头部的列表,可能是一个字符串列表。
render-blocking
(默认值为 false):渲染阻塞,布尔值。
response body info
是一个结构体,用于维护 Resource Timing 和 Navigation Timing 所需的响应体信息。它包含以下项目:[RESOURCE-TIMING] [NAVIGATION-TIMING]
encoded size
(默认值为 0):编码大小。decoded size
(默认值为 0):解码大小。content type
(默认值为空字符串):内容类型,ASCII 字符串。
要创建一个不透明的时间信息,给定一个 fetch 时间信息 timingInfo
,返回一个新的 fetch 时间信息,其开始时间和重定向后开始时间与 timingInfo
的开始时间相同。
要排队一个 fetch 任务,给定一个算法 algorithm
和一个全局对象或并行队列 taskDestination
,执行以下步骤:
- 如果
taskDestination
是一个并行队列,则将算法排队到taskDestination
。 - 否则,将全局任务排队到网络任务源,目标是
taskDestination
和algorithm
。
要序列化一个整数,将其表示为最短可能的十进制数字字符串。
这将由 Infra 中更具描述性的算法替换。请参见 infra/201。
2.1 URL
本地方案包括 "about"、"blob" 或 "data"。
如果 URL 的方案是本地方案,则该 URL 被认为是本地的。
这个定义也被引用政策(Referrer Policy)所使用。[REFERRER]
HTTP(S) 方案是 "http" 或 "https"。
获取方案(fetch scheme)包括 "about"、"blob"、"data"、"file" 或 HTTP(S) 方案。
HTTP(S) 方案和获取方案也被 HTML 所使用。[HTML]
2.2 HTTP
虽然获取(fetch)涵盖的内容不仅仅是 HTTP,但它借用了许多 HTTP 的概念,并将这些概念应用于通过其他方式获得的资源(例如数据 URL)。
HTTP 制表符或空格是 U+0009 TAB 或 U+0020 SPACE。
HTTP 空白字符是 U+000A LF、U+000D CR,或 HTTP 制表符或空格。
HTTP 空白字符仅对某些特定的结构有用,这些结构在 HTTP 头之外的上下文中会被重用(例如 MIME 类型)。对于 HTTP 头值,建议使用 HTTP 制表符或空格,在其他上下文中则建议使用 ASCII 空白字符。与 ASCII 空白字符不同,这排除了 U+000C FF。
HTTP 换行字节是 0x0A (LF) 或 0x0D (CR)。
HTTP 制表符或空格字节是 0x09 (HT) 或 0x20 (SP)。
HTTP 空白字节是 HTTP 换行字节或 HTTP 制表符或空格字节。
要从字符串输入中收集 HTTP 引号字符串,给定一个位置变量 position
和一个可选的布尔值 extract-value
(默认为 false):
设定
positionStart
为position
。设定
value
为空字符串。断言:输入中
position
处的代码点是 U+0022 (")。将
position
增加 1。当条件为真时:
从输入中收集一系列不是 U+0022 (") 或 U+005C () 的代码点,追加到
value
中。如果
position
超过输入末尾,则跳出循环。设定
quoteOrBackslash
为输入中position
处的代码点。将
position
增加 1。如果
quoteOrBackslash
是 U+005C (),则:如果
position
超过输入末尾,则将 U+005C () 追加到value
中,并跳出循环。将输入中
position
处的代码点追加到value
中。将
position
增加 1。
否则:
断言:
quoteOrBackslash
是 U+0022 (")。跳出循环。
如果
extract-value
为 true,则返回value
。返回从
positionStart
到position
(包括position
)之间的代码点。
示例
输入 | 输出 | 设置 extract-value 为 true 的输出 | 最终位置变量值 |
---|---|---|---|
""\" | ""\" | \" | 2 |
""Hello" World" | ""Hello"" | "Hello" | 7 |
""Hello \\ World\""" | ""Hello \\ World\""" | "Hello \ World"" | 18 |
在这些示例中,位置变量总是从 0 开始。
2.2.1 方法
方法是一个字节序列,它匹配方法标记的生成规则。
CORS 安全白名单方法是指 GET
、HEAD
或 POST
。
被禁止的方法是指与 CONNECT
、TRACE
或 TRACK
不区分字节大小写的匹配的方法。[HTTPVERBSEC1]、[HTTPVERBSEC2]、[HTTPVERBSEC3]
为了规范化方法,如果它与 DELETE
、GET
、HEAD
、OPTIONS
、POST
或 PUT
不区分字节大小写的匹配,则将其转为字节大写。
规范化是为了向后兼容性和 API 一致性,因为方法实际上是“区分大小写”的。
使用 patch
很可能会导致 405 Method Not Allowed
错误。PATCH
更可能成功。
方法没有任何限制。CHICKEN
是完全可以接受的(并不是 CHECKIN
的拼写错误)。除了那些被规范化的方法外,没有其他的大小写限制。Egg
或 eGg
也可以,但为了保持一致性,建议使用大写字母。
2.2.2 头部
HTTP 通常将头部称为“字段”或“头字段”。Web 平台使用更口语化的术语“头部”。[HTTP]
头部列表是零个或多个头部的列表。初始值为 « »。
头部列表本质上是一个特殊的多重映射:一个有序的键值对列表,可能包含重复的键。由于除 Set-Cookie
之外的头部在暴露给客户端 JavaScript 时总是会合并,因此实现可以选择更高效的表示方式,只要它们也支持用于 Set-Cookie
头部的相关数据结构即可。
要根据头部名称 name
和头部列表 list
中的字符串类型获取结构化字段值,请执行以下步骤。这些步骤返回 null 或结构化字段值。
断言:
type
是 "dictionary"、"list" 或 "item" 之一。让
value
为从list
中获取name
的结果。如果
value
为 null,则返回 null。让
result
为解析结构化字段的结果,输入字符串设为value
,头部类型设为type
。如果解析失败,则返回 null。
返回
result
。
获取结构化字段值故意不区分头部缺失与其值无法解析为结构化字段值。这确保了在 Web 平台上的处理一致性。
要设置结构化字段值给定一个元组(头部名称 name
、结构化字段值 structuredValue
),在头部列表 list
中:
让
serializedValue
为对structuredValue
执行序列化结构化字段算法的结果。在
list
中设置 (name, serializedValue)。
结构化字段值定义为 HTTP 可以(最终)以有趣和高效的方式序列化的对象。目前,Fetch 仅支持字节序列作为头部值,这意味着这些对象只能通过序列化设置到头部列表中,并且只能通过解析从头部列表中获取。未来,这些对象可能会被保留为端到端的对象。[RFC8941]
一个头部列表 list
包含头部名称 name
如果 list
包含一个名称与 name
不区分字节大小写的匹配头部。
要从头部列表 list
中获取头部名称 name
,请执行以下步骤。这些步骤返回 null 或头部值。
如果
list
不包含name
,则返回 null。返回
list
中所有与name
不区分字节大小写的匹配头部的值,以 0x2C 0x20(即逗号和空格)分隔,按顺序排列。
要获取、解码和拆分头部名称 name
从头部列表 list
中,执行以下步骤。这些步骤返回 null 或字符串列表。
让
value
为从list
中获取name
的结果。如果
value
为 null,则返回 null。返回获取、解码和拆分
value
的结果。
以下是 A
作为名称参数的获取、解码和拆分函数的实际情况:
头部(网络传输形式) | 输出 |
---|---|
A: nosniff, | « "nosniff", "" » |
A: nosniff | « "nosniff" » |
A: nosniff | « "nosniff" » |
A: | « "" » |
A: text/html;", x/x | « "text/html;", x/x" » |
A: text/html;" | « "text/html;" » |
A: x/x | « "x/x" » |
A: x/x;test="hi",y/y | « "x/x;test="hi"", "y/y" » |
A: x/x;test="hi" | « "x/x;test="hi"" » |
C: **bingo** | « "" » |
A: y/y | « "y/y" » |
A: x / x,,,1 | « "x / x", "", "", "1" » |
A: x / x | « "x / x" » |
A: , | « "" » |
A: 1 | « "1" » |
A: "1,2", 3 | « ""1,2"", "3" » |
A: "1,2" | « "1,2" » |
D: 4 | « "" » |
A: 3 | « "3" » |
获取、解码和拆分头部值
要获取、解码和拆分头部值 value
,执行以下步骤。这些步骤返回一个字符串列表。
让
input
为value
的同构解码结果。让
position
为input
的位置变量,初始指向input
的开始位置。让
values
为一个初始为空的字符串列表。让
temporaryValue
为一个空字符串。当
position
没有超过input
的末尾时:- 将从
input
中收集的不是 U+0022 (") 或 U+002C (,) 的代码点序列的结果追加到temporaryValue
中。 - 结果可能是空字符串。
- 如果
position
没有超过input
的末尾,则:- 如果
position
位置的代码点是 U+0022 ("), 则:- 将从
input
中收集的 HTTP 引号字符串的结果追加到temporaryValue
中。 - 如果
position
位置没有超过input
的末尾,则继续。
- 将从
- 否则:
- 断言:
position
位置的代码点是 U+002C (,)。 - 将
position
向前移动 1。 - 从
temporaryValue
的开始和结束处移除所有 HTTP 制表符或空格。 - 将
temporaryValue
追加到values
。 - 将
temporaryValue
设为空字符串。
- 断言:
- 如果
- 将从
返回
values
。
除了被祝福的调用点,以上算法不应被直接调用。请使用 get
、decode
和 split
。
向头部列表添加头部 (name, value)
要将头部 (name, value) 添加到头部列表 list
:
如果
list
包含name
,则将name
设置为第一个匹配头部的名称。- 如果
list
中存在多个匹配的头部,它们的名称将全部相同。
- 如果
将 (name, value) 追加到
list
中。
从头部列表删除头部名称
要从头部列表 list
中删除头部名称 name
,移除所有名称与 name
不区分字节大小写的匹配头部。
在头部列表中设置头部 (name, value)
要在头部列表 list
中设置头部 (name, value):
如果
list
包含name
,则将第一个匹配头部的值设置为value
并移除其他头部。否则,将 (name, value) 追加到
list
中。
在头部列表中合并头部 (name, value)
要在头部列表 list
中合并头部 (name, value):
如果
list
包含name
,则将第一个匹配头部的值设置为其值,后跟 0x2C 0x20(即逗号和空格),然后再跟上value
。否则,将 (name, value) 追加到
list
中。
合并在 XMLHttpRequest 和 WebSocket 协议握手中使用。
将头部名称转换为排序后的小写集合
要将头部名称转换为排序的小写集合,给定头部名称列表 headerNames
,执行以下步骤。这些步骤返回一个有序的头部名称集合。
让
headerNamesSet
为一个新的有序集合。对于
headerNames
中的每个名称,将名称的字节小写结果追加到headerNamesSet
中。返回将
headerNamesSet
按字节升序排序的结果。
对头部列表进行排序和合并
要对头部列表 list
进行排序和合并,执行以下步骤。这些步骤返回一个头部列表。
让
headers
为一个头部列表。让
names
为将list
中所有头部名称转换为排序的小写集合的结果。对于
names
中的每个名称:- 如果名称是
set-cookie
,则:- 让
values
为list
中所有与name
不区分字节大小写的匹配头部的所有值,按顺序排列。 - 对于
values
中的每个值:- 将 (name, value) 追加到
headers
中。
- 将 (name, value) 追加到
- 让
- 否则:
- 让
value
为从list
中获取name
的结果。 - 断言:
value
不为 null。 - 将 (name, value) 追加到
headers
中。
- 让
- 如果名称是
返回
headers
。
头部
一个头部是一个由名称(头部名称)和值(头部值)组成的元组。
头部名称是一个字节序列,它匹配字段名称标记生成规则。
头部值是一个字节序列,它符合以下条件:
- 没有前导或尾部 HTTP 制表符或空格字节。
- 不包含 0x00 (NUL) 或 HTTP 换行字节。
头部值的定义不是基于字段值标记生成规则,因为它不兼容已部署的内容。
规范化字节序列
要规范化字节序列 potentialValue
,移除 potentialValue
中的所有前导和尾部 HTTP 空白字节。
确定头部是否为 CORS 安全白名单请求头
要确定头部 (name, value) 是否为 CORS 安全白名单请求头,执行以下步骤:
如果
value
的长度大于 128,则返回 false。将
name
转为字节小写并根据结果进行判断:accept
- 如果
value
包含 CORS 不安全请求头字节,则返回 false。
- 如果
accept-language
content-language
- 如果
value
包含一个不在 0x30 (0) 到 0x39 (9) 的范围内的字节,不在 0x41 (A) 到 0x5A (Z) 的范围内,不在 0x61 (a) 到 0x7A (z) 的范围内,并且不是 0x20 (SP)、0x2A (*)、0x2C (,)、0x2D (-)、0x2E (.)、0x3B (;) 或 0x3D (=),则返回 false。
- 如果
content-type
- 如果
value
包含 CORS 不安全请求头字节,则返回 false。 - 让
mimeType
为解析value
的同构解码结果。 - 如果
mimeType
解析失败,则返回 false。 - 如果
mimeType
的本质不是 "application/x-www-form-urlencoded"、"multipart/form-data" 或 "text/plain",则返回 false。 - 这故意不使用提取 MIME 类型,因为该算法比较宽松,服务器不期望实现它。
- 如果使用提取 MIME 类型,以下请求将不会导致 CORS 预检,并且服务器上的天真的解析器可能将请求体视为 JSON:
fetch("https://victim.example/naïve-endpoint", {method: "POST",headers: [["Content-Type", "application/json"],["Content-Type", "text/plain"]],credentials: "include",body: JSON.stringify(exerciseForTheReader) });
- 如果
range
- 让
rangeValue
为解析单个范围头部值的结果,给定value
和 false。 - 如果
rangeValue
解析失败,则返回 false。 - 如果
rangeValue[0]
为 null,则返回 false。 - 由于 web 浏览器历史上没有发出如
bytes=-500
的范围,这个算法不将它们列入白名单。 - 否则返回 false。
- 返回 true。
- 让
有限的例外情况适用于
Content-Type
头部的白名单,如 CORS 协议异常所记录。
CORS 不安全请求头字节
CORS 不安全请求头字节是指以下条件之一为真的字节 byte
:
byte
小于 0x20 且不是 0x09 HT。byte
是 0x22 (")、0x28 (左括号)、0x29 (右括号)、0x3A (:)、0x3C (<)、0x3E (>)、0x3F (?)、0x40 (@)、0x5B ([)、0x5C ()、0x5D (])、0x7B ({)、0x7D (}) 或 0x7F DEL。
CORS 不安全请求头名称
给定头部列表 headers
,CORS 不安全请求头名称的确定方法如下:
让
unsafeNames
为一个新的列表。
让
potentiallyUnsafeNames
为一个新的列表。让
safelistValueSize
为 0。对于每个头部
headers
:- 如果头部不是 CORS 安全白名单请求头,则将头部名称追加到
unsafeNames
。 - 否则,将头部名称追加到
potentiallyUnsafeNames
并将safelistValueSize
增加头部值的长度。
- 如果头部不是 CORS 安全白名单请求头,则将头部名称追加到
如果
safelistValueSize
大于 1024,则对于每个名称的potentiallyUnsafeNames
,将名称追加到unsafeNames
。返回将
unsafeNames
转换为排序的小写集合的结果。
CORS 非通配符请求头名称
CORS 非通配符请求头名称是指与 Authorization
不区分字节大小写的匹配头部名称。
特权非 CORS 请求头名称
特权非 CORS 请求头名称是与以下之一不区分字节大小写的头部名称:
Range
。
这些是可以由特权 API 设置的头部,并且在其相关请求对象被复制时将被保留,但如果请求被非特权 API 修改则会被移除。
Range
头部通常用于下载和媒体获取。
辅助函数:为请求添加范围头部
一个辅助函数用于将范围头部添加到特定请求。
CORS 安全白名单响应头名称
给定头部名称列表 list
,CORS 安全白名单响应头名称是与以下之一不区分字节大小写的头部名称:
Cache-Control
Content-Language
Content-Length
Content-Type
Expires
Last-Modified
Pragma
任何列表中不被禁止的响应头名称。
非 CORS 安全白名单请求头名称
非 CORS 安全白名单请求头名称是与以下之一不区分字节大小写的头部名称:
Accept
Accept-Language
Content-Language
Content-Type
确定头部是否为非 CORS 安全白名单请求头
要确定头部 (name, value) 是否为非 CORS 安全白名单请求头,执行以下步骤:
如果
name
不是非 CORS 安全白名单请求头名称,则返回 false。返回头部 (name, value) 是否为 CORS 安全白名单请求头。
禁止请求头
如果头部 (name, value) 是禁止的请求头,则这些步骤将返回 true:
如果
name
与以下之一不区分字节大小写,则返回 true:Accept-Charset
Accept-Encoding
Access-Control-Request-Headers
Access-Control-Request-Method
Connection
Content-Length
Cookie
Cookie2
Date
DNT
Expect
Host
Keep-Alive
Origin
Referer
Set-Cookie
TE
Trailer
Transfer-Encoding
Upgrade
Via
如果
name
转为字节小写后以proxy-
或sec-
开头,则返回 true。如果
name
与以下之一不区分字节大小写,则:X-HTTP-Method
X-HTTP-Method-Override
X-Method-Override
让
parsedValues
为获取、解码和拆分value
的结果。对于每个
parsedValues
的方法:如果同构编码的method
是禁止方法,则返回 true。
返回 false。
这些是禁止的,以便用户代理保持完全控制。
以 Sec-
开头的头部名称保留以允许新头部的发行,这些新头部在使用 fetch 的 API 中允许开发人员控制头部时是安全的,例如 XMLHttpRequest。 [XHR]
Set-Cookie
头部语义上是响应头部,因此在请求中没有用处。由于 Set-Cookie
头部不能合并,因此它们需要在 Headers 对象中更复杂的处理。在这里禁止它是为了避免将这种复杂性泄漏到请求中。
禁止响应头名称
禁止响应头名称是与以下之一不区分字节大小写的头部名称:
Set-Cookie
Set-Cookie2
请求体头部名称
请求体头部名称是与以下之一不区分字节大小写的头部名称:
Content-Encoding
Content-Language
Content-Location
Content-Type
提取头部值
根据头部的名称提取头部值,执行以下步骤:
- 如果解析头部值时,按照头部名称的 ABNF 规则失败,则返回失败。
- 根据头部名称的 ABNF 规则,返回解析头部值得到的一个或多个值。
提取头部列表值
根据头部名称 name
和头部列表 list
提取头部列表值,执行以下步骤:
- 如果列表中不包含名称
name
,则返回 null。 - 如果名称
name
的 ABNF 规则只允许一个头部,但列表中包含多个,则返回失败。 - 如果需要不同的错误处理,首先提取所需的头部。
- 让
values
为空列表。 - 对于列表中包含名称
name
的每个头部header
:- 让
extract
为从头部header
中提取的头部值的结果。 - 如果
extract
为失败,则返回失败。 - 将
extract
中的每个值按顺序附加到values
。
- 让
- 返回
values
。
构建内容范围
根据整数 rangeStart
、整数 rangeEnd
和整数 fullLength
构建内容范围,执行以下步骤:
- 让
contentRange
为bytes
。 - 将
rangeStart
序列化并以同构编码追加到contentRange
。 - 将 0x2D(-)追加到
contentRange
。 - 将
rangeEnd
序列化并以同构编码追加到contentRange
。 - 将 0x2F(/)追加到
contentRange
。 - 将
fullLength
序列化并以同构编码追加到contentRange
。 - 返回
contentRange
。
解析单个范围头部值
根据字节序列 value
和布尔值 allowWhitespace
解析单个范围头部值,执行以下步骤:
- 让
data
为value
的同构解码。 - 如果
data
不以 "bytes" 开头,则返回失败。 - 让
position
为data
的位置变量,最初指向data
的第 5 个字符位置。 - 如果
allowWhitespace
为 true,从data
中收集一系列 HTTP 制表符或空格的字符,起始位置为position
。 - 如果
data
中position
处的字符不是 U+003D(=),则返回失败。 - 将
position
向前移动 1。 - 如果
allowWhitespace
为 true,从data
中收集一系列 HTTP 制表符或空格的字符,起始位置为position
。 - 让
rangeStart
为从data
中收集的一系列 ASCII 数字字符,起始位置为position
。 - 如果
rangeStart
不是空字符串,则将rangeStart
解释为十进制数,得到rangeStartValue
;否则为 null。 - 如果
allowWhitespace
为 true,从data
中收集一系列 HTTP 制表符或空格的字符,起始位置为position
。 - 如果
data
中position
处的字符不是 U+002D(-),则返回失败。 - 将
position
向前移动 1。 - 如果
allowWhitespace
为 true,从data
中收集一系列 HTTP 制表符或空格的字符,起始位置为position
。 - 让
rangeEnd
为从data
中收集的一系列 ASCII 数字字符,起始位置为position
。 - 如果
rangeEnd
不是空字符串,则将rangeEnd
解释为十进制数,得到rangeEndValue
;否则为 null。 - 如果
position
没有超出data
的末尾,则返回失败。 - 如果
rangeEndValue
和rangeStartValue
都为 null,则返回失败。 - 如果
rangeStartValue
和rangeEndValue
都是数字,并且rangeStartValue
大于rangeEndValue
,则返回失败。 - 返回
(rangeStartValue, rangeEndValue)
。
范围结束或开始可以省略,例如 bytes=0-
或 bytes=-500
是有效范围。
解析单个范围头部值成功地覆盖了允许的范围头部值的子集,但这是用户代理在请求媒体或恢复下载时最常使用的格式。这种范围头部值的格式可以通过添加范围头部来设置。
默认 User-Agent
值
默认的 User-Agent
值是为 User-Agent
头部定义的实现特定头部值。
文档 Accept
头部值
文档的 Accept
头部值是 text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
。
2.2.3 状态码
状态码是范围在 0 到 999 之间的整数(包括 0 和 999)。
有关将 HTTP/1 的状态码映射到这一概念的各种边缘情况,参见问题 #1156。
- 空体状态码 是指状态码为 101、103、204、205 或 304 的状态码。
- 成功状态码 是指状态码在 200 到 299 之间(包括 200 和 299)的状态码。
- 重定向状态码 是指状态码为 301、302、303、307 或 308 的状态码。
2.2.4 请求体
请求体包括:
- 一个流(一个 ReadableStream 对象)。
- 一个来源(null、字节序列、Blob 对象或 FormData 对象),初始值为 null。
- 一个长度(null 或整数),初始值为 null。
克隆请求体
要克隆请求体 body
,执行以下步骤:
- 让 « out1, out2 » 为
body
流的 tee 操作结果。 - 将
body
的流设置为out1
。 - 返回一个新请求体,其流为
out2
,其他成员与原body
相同。
获取字节序列请求体
要将字节序列 bytes
转换为请求体,返回安全提取字节序列 bytes
的请求体。
增量读取请求体
要增量读取请求体 body
,给定算法 processBodyChunk
、processEndOfBody
、processBodyError
,以及一个可选的 taskDestination
(默认为 null),执行以下步骤:
processBodyChunk
必须是一个接受字节序列的算法。processEndOfBody
必须是一个不接受参数的算法。processBodyError
必须是一个接受异常的算法。
如果 taskDestination
为 null,则将 taskDestination
设置为启动新并行队列的结果。
- 获取
body
流的读取器,并将其赋值给reader
。 - 这个操作不会抛出异常。
- 执行增量读取循环,给定
reader
、taskDestination
、processBodyChunk
、processEndOfBody
和processBodyError
。
执行增量读取循环
给定一个 ReadableStreamDefaultReader
对象 reader
、并行队列或全局对象 taskDestination
、算法 processBodyChunk
、算法 processEndOfBody
和算法 processBodyError
,执行以下步骤:
设定
readRequest
为以下读取请求:- chunk steps,给定 chunk
- 设定
continueAlgorithm
为 null。
如果
chunk
不是Uint8Array
对象,则将continueAlgorithm
设定为以下步骤:运行processBodyError
,给定一个TypeError
。否则:
- 让
bytes
为chunk
的副本。 - 强烈建议实现使用避免这种副本的实现策略(如果可能)。
- 设定
continueAlgorithm
为以下步骤:- 运行
processBodyChunk
,给定bytes
。 - 执行增量读取循环,给定
reader
、taskDestination
、processBodyChunk
、processEndOfBody
和processBodyError
。 - 将
continueAlgorithm
排队到taskDestination
。
- 运行
- close steps:
- 将
processEndOfBody
排队到taskDestination
。
- 将
- error steps,给定
e
:- 将
processBodyError
排队到taskDestination
,传递e
。
- 将
- 让
从
reader
读取一个 chunk,给定readRequest
。
完全读取请求体
要完全读取请求体 body
,给定算法 processBody
、算法 processBodyError
和可选的 taskDestination
(默认为 null),执行以下步骤:
processBody
必须是一个接受字节序列的算法。processBodyError
必须是一个可选地接受异常的算法。
- 如果
taskDestination
为 null,则将taskDestination
设置为启动新并行队列的结果。 - 设定成功步骤
successSteps
为:将任务排队以在taskDestination
上运行processBody
,传递字节序列bytes
。 - 设定错误步骤
errorSteps
为:将任务排队以在taskDestination
上运行processBodyError
,传递异常exception
。 - 获取
body
流的读取器。如果这抛出了异常,则用该异常运行errorSteps
并返回。 - 从
reader
中读取所有字节,给定successSteps
和errorSteps
。
请求体与类型
一个带类型的请求体是一个元组,包括一个请求体(body)和一个类型(header 值或 null)。
处理内容编码
要处理给定编码 codings
和字节序列 bytes
的内容编码,执行以下步骤:
- 如果
codings
不被支持,则返回字节序列bytes
。 - 返回使用
codings
解码字节序列bytes
的结果(如果解码没有产生错误),否则返回失败。
2.2.5 请求
本节详细描述了请求的工作原理。开始时,请参见“设置请求”。
请求的输入 是一个请求对象。
请求的相关方法(method)是一个方法。除非另有说明,否则默认为
GET
。- 在重定向过程中,这可能会被更新为
GET
,具体描述见 HTTP fetch。
- 在重定向过程中,这可能会被更新为
请求的相关 URL(URL)是一个 URL。
- 实现者被鼓励将其设为请求 URL 列表中的第一个 URL 的指针。它作为一个单独的字段提供,仅为其他标准在 Fetch 中方便使用。
请求的相关本地 URL 仅限标志(local-URLs-only flag)。除非另有说明,否则为未设置。
请求的相关头部列表(header list)是一个头部列表。除非另有说明,否则默认为 « »。
请求的相关不安全请求标志(unsafe-request flag)。除非另有说明,否则为未设置。
- 不安全请求标志由
fetch()
和XMLHttpRequest
等 API 设置,以确保根据提供的方法和头部列表进行 CORS 预检请求。它并不免除 API 禁止使用被禁止的方法和请求头部。
- 不安全请求标志由
请求的相关体(body)可以是 null、字节序列或一个体。除非另有说明,否则默认为 null。
- 字节序列将在 fetch 早期安全提取为一个体。在 HTTP fetch 的过程中,由于某些重定向,这个字段可能会被设置为 null。
请求的相关客户端(client)可以是 null 或环境设置对象。
请求的相关保留客户端(reserved client)可以是 null、环境或环境设置对象。除非另有说明,否则默认为 null。
- 这仅用于导航请求和工作者请求,但不用于服务工作者请求。它引用一个导航请求的环境或工作者请求的环境设置对象。
请求的相关替换客户端 ID(replaces client id)是一个字符串。除非另有说明,否则默认为空字符串。
- 这仅用于导航请求。它是目标浏览上下文的活动文档环境设置对象的 ID。
请求的相关窗口(window)可以是 "no-window"、"client" 或一个其全局对象是 Window 对象的环境设置对象。除非另有说明,否则默认为 "client"。
- 在获取过程中,“client”值会变更为 “no-window” 或请求的客户端。这为标准提供了一个方便的方式,无需显式设置请求的窗口。
请求的相关 boolean keepalive。除非另有说明,否则默认为 false。
- 这可以用于允许请求超越环境设置对象的生命周期,例如,
navigator.sendBeacon()
和 HTML img 元素使用它。将此设置为 true 的请求需要额外的处理要求。
- 这可以用于允许请求超越环境设置对象的生命周期,例如,
请求的相关启动器类型(initiator type)可以是 null、"audio"、"beacon"、"body"、"css"、"early-hints"、"embed"、"fetch"、"font"、"frame"、"iframe"、"image"、"img"、"input"、"link"、"object"、"ping"、"script"、"track"、"video"、"xmlhttprequest" 或 "other"。除非另有说明,否则默认为 null。 [RESOURCE-TIMING]
请求的相关服务工作者模式(service-workers mode)可以是 "all" 或 "none"。除非另有说明,否则默认为 "all"。
- 这决定了哪些服务工作者将接收此 fetch 的 fetch 事件。
- "all":相关服务工作者将获得此 fetch 的 fetch 事件。
- "none":没有服务工作者将获得此 fetch 的事件。
请求的相关启动器(initiator)可以是空字符串、"download"、"imageset"、"manifest"、"prefetch"、"prerender" 或 "xslt"。除非另有说明,否则默认为空字符串。
- 请求的启动器目前不特别细化,因为其他规范不要求这样做。它主要是一个规范设备,用于帮助定义 CSP 和混合内容。它不暴露给 JavaScript。 [CSP] [MIX]
请求的相关目标(destination)可以是空字符串、"audio"、"audioworklet"、"document"、"embed"、"font"、"frame"、"iframe"、"image"、"json"、"manifest"、"object"、"paintworklet"、"report"、"script"、"serviceworker"、"sharedworker"、"style"、"track"、"video"、"webidentity"、"worker" 或 "xslt"。除非另有说明,否则默认为空字符串。
- 这些在
RequestDestination
中体现,但 "serviceworker" 和 "webidentity" 作为目标的 fetch 会跳过服务工作者。
- 这些在
请求的目标是类似脚本的(script-like),如果它是 "audioworklet"、"paintworklet"、"script"、"serviceworker"、"sharedworker" 或 "worker"。
- 使用脚本类似的算法时,还应考虑 "xslt",因为它也可能导致脚本执行。它未包含在列表中,因为它不总是相关,并可能需要不同的行为。
下表展示了请求的启动器、目标、CSP 指令和特性之间的关系。它不详尽地列出了所有特性。特性需要在其各自的标准中定义相关值。
启动器 | 目标 | CSP 指令 | 特性 |
---|---|---|---|
"" | "report" | — | CSP、NEL 报告。 |
"document" | HTML 的导航算法(仅顶级)。 | ||
"frame" | "child-src" | HTML 的 | |
"iframe" | "child-src" | HTML 的 > | |
"" | "connect-src" | navigator.sendBeacon()、EventSource、HTML 的 和 、fetch()、XMLHttpRequest、WebSocket、Cache API | |
"object" | "object-src" | HTML 的 | |
"embed" | "object-src" | HTML 的 | |
"audio" | "media-src" | HTML 的 | |
"font" | "font-src" | CSS 的 @font-face | |
"image" | "img-src" | HTML 的 、/favicon.ico 资源、SVG 的 、CSS 的 background-image、CSS 的 cursor、CSS 的 list-style-image 等 | |
"audioworklet" | "script-src" | audioWorklet.addModule() | |
"paintworklet" | "script-src" | CSS.paintWorklet.addModule() | |
"script" | "script-src" | HTML 的 |