深入剖析XMLHttpRequest规范 / 译文 - 陈帅华

标签:
前端异步加载javascripthtml5 |
分类: 前端 |
原文链接
https://www.shuaihua.cc/article/1506043812751/top_picture.jpeg/
WHATWG原文: XMLHttpRequest Living Standard — Last Updated 8 September 2017
概要
XMLHttpRequest标准为客户端和服务器端传输数据提供了脚本化的客户端功能API。
目录
-
1 介绍
-
2 一致性
-
3 术语
-
4
XMLHttpRequest接口 -
5
FormData 接口 -
6
ProgressEvent 接口 -
参考
-
鸣谢
-
索引
-
接口描述信息
1 介绍
本章未规范化。
XMLHttpRequest
由于历史遗留原因,XMLHttpRequest
使用案例
1.或许XML文档数据
function processData(data) {
// taking care of data
}
function handler() {
if(this.status == 200 &&
this.responseXML != null &&
this.responseXML.getElementById('test').textContent) {
// success!
processData(this.responseXML.getElementById('test').textContent);
} else {
// something went wrong
…
}
}
var client = new XMLHttpRequest();
client.onload = handler;
client.open("GET", "unicorn.xml");
client.send();
2.如果你只是想向服务器端发送信息
function log(message) {
var client = new XMLHttpRequest();
client.open("POST", "/log");
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send(message);
}
3.或者你想获取文档在服务器端的状态信息
function fetchStatus(address) {
var client = new XMLHttpRequest();
client.onload = function() {
// in case of network errors this might not give reliable results
returnStatus(this.status);
}
client.open("HEAD", address);
client.send();
}
1-1 历史之源
XMLHttpRequest对象是WHATWG组织在HTML标准化之路上推出的接口之一(基于多年前微软在这方面的部分已实现的功能与机制)。在2006年,该规范移交至W3C,一些扩展功能与机制(请求进度事件
和
人们可以从以下的邮件列表档案中寻找当时讨论该草案的过程:
2 一致性
该规范的所有的图表,用例和笔记都为标准化,在每一章中也都会明确指出为标准化,凡是未明确指出的都为标准化的,人们可以放心使用。
“MUST”,“MUST
NOT”,“REQUIRED”,“SHOULD”,“SHOULD
NOT”,“RECOMMENDED”,“MAY”
2-1 可扩展性
我们强烈鼓励用户代理(浏览器厂商,设备厂商)、工作组和其他有兴趣的团体与WHATWG社区一起讨论新的功能。
3 术语
该规范的DOM,DOM解析和序列化,编码,远程获取,文件API,HTML,URL,Web IDL和XML中使用的术语,全部超链接:
[DOM]
使用HTML的常用排版方式
规范中的**user
credentials*术语,指的是cookie,HTTP证书和TLS客户端证书,特别要指出的是,它并不代表代理证书或者
4 XMLHttpRequest接口
接口描述信息
[Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequestEventTarget : EventTarget {
// event handlers
attribute EventHandler onloadstart;
attribute EventHandler onprogress;
attribute EventHandler onabort;
attribute EventHandler onerror;
attribute EventHandler onload;
attribute EventHandler ontimeout;
attribute EventHandler onloadend;
};
[Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
};
enum XMLHttpRequestResponseType {
"",
"arraybuffer",
"blob",
"document",
"json",
"text"
};
[Constructor,
Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
attribute EventHandler onreadystatechange;
// states
const unsigned short UNSENT = 0;
const unsigned short OPENED = 1;
const unsigned short HEADERS_RECEIVED = 2;
const unsigned short LOADING = 3;
const unsigned short DONE = 4;
readonly attribute unsigned short readyState;
// request
void open(ByteString method, USVString url);
void open(ByteString method, USVString url, boolean async, optional USVString? username = null, optional USVString? password = null);
void setRequestHeader(ByteString name, ByteString value);
attribute unsigned long timeout;
attribute boolean withCredentials;
[SameObject] readonly attribute XMLHttpRequestUpload upload;
void send(optional (Document or BodyInit)? body = null);
void abort();
// response
readonly attribute USVString responseURL;
readonly attribute unsigned short status;
readonly attribute ByteString statusText;
ByteString? getResponseHeader(ByteString name);
ByteString getAllResponseHeaders();
void overrideMimeType(DOMString mime);
attribute XMLHttpRequestResponseType responseType;
readonly attribute any response;
readonly attribute USVString responseText;
[Exposed=Window] readonly attribute Document? responseXML;
};
每一个
每一个
每一个
4-1 构造器
client = new XMLHttpRequest()
// 返回一个新的 XMLHttpRequest 对象。
XMLHttpRequest()
4-2 垃圾回收机制
每一个
如果
4-3 事件处理器
如下的事件处理器(和他们对应的处理的事件类型),必须作为
event handler | event handler event type |
---|---|
|
loadstart |
|
progress |
|
abort |
|
error |
|
load |
|
timeout |
|
loadend |
如下的事件处理器(和他相应的事件类型),必须被支持,并且完全作为
event handler | event handler event type |
---|---|
|
readystatechange |
4-4 状态码
client.readyState
// 返回客户端的状态
readyState
unsent |
|
The object has been constructed. |
opened |
|
The open() setRequestHeader() send() |
headers received |
(numeric
value 2) |
All redirects (if any) have been followed and all
HTTP headers of the |
loading |
|
The |
done |
|
The data transfer has been completed or something went wrong during the transfer (e.g. infinite redirects). |
4-5 请求
每一个
自定义请求头的初始状态的是空的header list。
请求体
同步标志,上传完成标志,上传监听器标志,超时标志的初始化状态为 unset。
在
4-5-1 open()
方法
client . open(method, url [, async = true [, username = null [, password = null]]])
设置
如果方法不是一个可用的HTTP方法,或者 ur 不能被接续,则l抛出一个 语法错误(SyntaxError)。
如果方法因为不敏感的大小写('CONNECT','TRACE','TRACK'),则抛出一个安全错误(SecurityError)。
如果没有采用异步请求的方式,当前的全局对象是一个Window对象,并且超时(timeout)属性不为0或者responseType属性不为空的字符串,则抛出不可用的权限错误(InvalidAccessError)。
同步的 XMLHttpRequest请求已经渐渐的被网络平台开发者所淘汰,因为这严重影响到用户体验。如果当前全局对象为Window,请开发者切勿将是否开启异步加载设为 false。我们强烈建议用户代理借助浏览器的开发者工具可以通过抛出 InvalidAccessError 的错误警告开发者们不要这样做。
open(method,
url)
- 1、如果上下文对象的相关设置对象有一个可用的文档,并且没有被完全激活,抛出 InvalidStateError 错误。
- 2、如果方法不可用,抛出 SyntaxError 错误。
- 3、如果方法是被禁用的,抛出 SecurityError 错误。
- 4、序列化方法。
- 5、使用上下文中的API base URL 解析传入的 url,并赋值给 parsedURL。
- 6、如果 parsedURL 解析失败,抛出 SyntaxError 错误。
-
7、如果开发者省略了
async(是否异步加载) 参数。默认设置为 true(开启异步加载),并且设置 username 和 password 为 null。
遗憾的是,默认的 aysnc 参数并不为 undefined
-
8、如果 parsedURL 的主机地址不为空,执行以下步骤:
- 如果 username 参数不为空,将 parsedURL 加入 username 。
- 如果 password 参数不为空,将 parsedURL 加入password。
-
9、如果一部标志已开启,且当前的全局对象为 Window,并且超时属性不为0
或者
responseType 属性不为空字符串,那么抛出 InvalidAccessError 错误。 -
10、使用如下的对象设置可变量:
-
重置
send() 标志 和 *upload listener * 标志。 - 为方法设置请求方法。
- 设置请求地址为 parsedURL。
- 如果异步标志为 false,设置同步标志,否则重置同步标志。
- 清空用户自定义的请求头。
- 设置接受字节为空的字节序列。
- 设置响应对象为 null。
-
重置
-
12、如果 state 为开放,执行以下子步骤:
- 设置 state 为 opened。
-
触发
readystatechange 事件。
之所有 open() 方法有两个构造器,是因为过去的编辑器的限制。
4-5-2 setRequestHeader()
方法
client . setRequestHeader(name, value)
将用户自定义的请求头们合并到待发送的请求头。
如果当前状态为 not opened 或者 send() 标志被设置(也就是无法再设置请求头了),则抛出 InvalidStateError(不可用的状态错误) 异常。
如果 name 参数不是头信息的合法属性或者 value 也不是请求头的合法值,则抛出 SyntaxError(语法错误) 异常。
正如下方算法指出的,某些请求头不会被设置。如果他们在 send() 方法调用前没有被开发者明确的设置,则其他的一些确定的请求头用户代理将由用户代理掌控。
setRequestHeader(name, value)
-
1、如果
state 未打开,抛出 InvalidStateError(不可用的状态错误) 异常。 - 2、如果 send() 标志已经被设置,抛出 InvalidStateError(不可用的状态错误)异常。
- 3、序列化值。
- 4、如果 name 参数不正确,则抛出 SyntaxError(语法错误) 异常。
空的字节序列代表空的请求值。
- 5、如果 name 参数是一个被禁止的请求头名称则终止这些步骤。
- 6、联合用户自定义的请求头信息 name/value 。
用例
该用户演示了如果对同意请求头的属性设置了两次会发生什么:
// The following script:
var client = new XMLHttpRequest();
client.open('GET', 'demo.cgi');
client.setRequestHeader('X-Test', 'one');
client.setRequestHeader('X-Test', 'two');
client.send();
// …results in the following header being sent:
// X-Test: one, two
4-5-3 timeout
属性
client . timeout
超时时间将会以毫秒作为单位,当开发者设置了一个非零的值时,如果经过了超时的时长仍未完成并返回响应信息,将导致获取远程资源的失败。并且同步的标志为被设置,一个
当设置:如果同步的标志被设置并且当前的全局对象为Window对象,则抛出 InvalidAccessError(不可用的权限错误) 异常 。
timeout
设置
- 1、如果当前全局对象是 Window 对象,并且同步标志被设置,则抛出 InvalidAccessError(不可用的权限错误) 异常。
- 2、设置它自身的值为新的值。
这意味着,即使正在获取远程资源,也可以随时设置 timeout 属性,如果你这样做了,接口将会计算自开始请求获取远程响应已过去的时间。
4-5-4 withCredentials
属性
client . withCredentials
当
withCredentials
设置
-
1、如果
state 标志为 not unsent 或者 opened,抛出 InvalidStateError(不可用的状态错误) 异常。 -
2、如果
send() 标记已经被设置。抛出 InvalidStateError(不可用的状态错误) 异常, -
3、设置withCredentials
属性值为给定的值。
当获取 *same-origin* 资源,withCredentials 属性没有任何作用
4-5-5 upload()
方法
client . upload
返回相关联的 XMLHttpRequest 对象 ,其可被用来收集当数据正在向服务器传输时的传输信息。
upload
早期的规范说明中,每一个 *XMLHttpRequest* 对象都有一个相关联的 *XMLHttpRequestUpload* 对象。
4-5-6 send()
方法
client . send([body = null])
初始化这一请求,该方法的参数项可选的提供请求体,如果开发者使用 *GET* 或者 *HEAD* 请求方法,则该请求体将会被忽略。如果 *not opened* 或者 *send()* 标志已被设置,则抛出 *InvalidStateError*(不可用的状态错误) 异常。
send(body)
-
1、如果
state 为 not opened,抛出 InvalidStateError(不可用的状态错误) 异常。 -
2、如果已经设置了
send() 标志,则抛出 InvalidStateError(不可用的状态错误) 异常。 -
3、如果请求方法为
GET 或者 HEAD ,则将 body 替换为 null。 -
4、如果
body 为 null ,执行以下步骤 -
否则,让
encoding 和 mimeType 为 null ,并且执行以下规则,并将其转换至 body 中。 Document 设置 encoding 为 UTF-8。 如果 body 是 HTML document,设置 mimeType 为 text/html,否则重写 application/xml,之后将 ;charset=UTF-8 添加到 mimeType 中。 设置 body 的请求体,序列化,转换为 Unicode 并使用 utf-8 解码。 BodyInit 如果 body 为字符串,设置 encoding 为UTF-8; 设置 请求体 和 mimeType 到 extracting body 中。 如果 mimeType 为 non-null 并且 用户自定义的请求头不包含 Content-Type ,那么将 Content-Type 和 mimeType 添加到用户请求头中。 否则,如果请求头中 byte-case-insensitive 匹配到了 Content-Type 为可用的 mimeType,其有 charset 参数,并且不是 byte-case-insensitive ,然后 encoding 为 not null,然后设置所有的 charset 参数(值不为 byte-case-insensitive)。
-
否则,让
-
5、如果一个或更多个事件监听器被注册到相关的
XMLHttpRequestUpload 对象,那么设置 upload listener flag。 -
6、初始化
req 为一个新的 request,使用如下步骤初始化: - method
- url
- header list
-
unsafe-request flag
- Set.
- body
- client
-
synchronous flag
-Set if the synchronous flagis set. -
mode
- "cors"
-
use-CORS-preflight flag
- Set ifupload listener flagis set.
-
credentials mode
-
如果
withCredentials 属性的之 true,否则设置 include 和 same-origi。
-
如果
-
use-URL-credentials flag
-
设置如果
request URL's username不为空字符串或者 request URL's password 为 *non-null。
-
设置如果
-
7、重置
upload complete flag. -
8、重置
timed out flag. -
9、如果请求body为空,设置
upload complete flag -
10、设置
send() 标志。 -
11、如果
synchronous flag被重置,执行如下子步骤: -
1、使用0和0触发
loadstart 这一进度事件。 -
2、如果
upload complete flag 被重置并且 upload listener flag,那么 fire a progress event,该进度事件叫做 loadstart,XMLHttpRequestUpload 对象。 -
3、如果
state 为 not opened 或者 send() 标志以重置,那么直接返回。 -
4、获取
req ,处理 ** networking task source
-
1、使用0和0触发
4-5-7 abort()
方法
client . abort()
取消一切网络相关的请求活动。
readystatechange事件将不会被派发。
4-6 响应
每一个
XMLHttpRequest
4-6-1 responseURL()
属性
如果response的url
4-6-2 status()
属性
4-6-3 statusText()
属性
statusText
4-6-4 getResponseHeader()
方法
getResponseHeader(name)
-
1、如果
response 的 header list does not contain 名称,那么返回 null。 -
2、返回
combined value为给定的名称并且response的 header list
The Fetch Standard
filters
var client = new XMLHttpRequest();
client.open("GET", "unicorns-are-teh-awesome.txt", true);
client.send();
client.onreadystatechange = function() {
if(this.readyState == this.HEADERS_RECEIVED) {
print(client.getResponseHeader("Content-Type"));
}
}
print
text/plain; charset=UTF-8
4-6-5 getAllResponseHeaders()
方法
当调用
-
1、初始化
output 为空的字节序列。 -
2、初始化
headers ,将 response 的 header list 执行 sort and combine 处理,处理结果赋值给 headers。 -
3、对于
headers 中每一个 header 的名值对,使用 0x3A 0x20 加以修饰。 -
4、返回
output。
The Fetch Standard filters response’s header list. [FETCH]
用例
var client = new XMLHttpRequest();
client.open("GET", "narwhals-too.txt", true);
client.send();
client.onreadystatechange = function() {
if(this.readyState == this.HEADERS_RECEIVED) {
print(this.getAllResponseHeaders());
}
}
print
connection: Keep-Alive
content-type: text/plain; charset=utf-8
date: Sun, 24 Oct 2004 04:58:38 GMT
keep-alive: timeout=15, max=99
server: Apache/1.3.31 (Unix)
transfer-encoding: chunked
4-6-6 响应体
response MIME type
-
1、初始化
mimeType。 -
2、如果
mimeType 为空的字节序列,那么设置 mimeType 为 text/xml。 -
3、返回
mimeType。
override MIME
type
response
charset
XMLHttpRequest
4-6-7 overrideMineType()
方法
client . overrideMimeType(mime)
这样设置让响应头的
如果
overrideMimeType(mime)
-
1、如果
state 为 loading 或者 done ,抛出 InvalidStateError(不可用的状态错误) 异常。 -
2、设置
override MIME type 为 application/octet-stream。 -
3、如果
mime 是可解析的 MIME type, 那么设置 override MIME type 为他自己的 MIME type portion。 -
4、如果
override MIME type 拥有 charset 参数,那么设置 ovveride charset 为其值。
4-6-8 responseType
属性
client . responseType [ = value ]
返回响应的数据类型。
可以赋值,改变响应类型,默认的为空字符串,arraybuffer,blob,document,json
当设置:如果
当设置:如果
当设置:如果
responseType
4-6-9 response
属性
client . response
返回响应体。
4-6-10 responseText
属性
client . responseText
返回文本响应。
如果
4-6-11 responseXML
属性
client . responseXML
返回
如果
4-7 事件概要
本章节内容未标准化。
下方的事件由
Event name | Interface | Dispatched when… |
---|---|---|
|
Event |
The readyState |
|
ProgressEvent |
The fetch initiates. |
|
ProgressEvent |
Transmitting data. |
|
ProgressEvent |
When the fetch has been aborted. For instance, by
invoking the abort() |
|
ProgressEvent |
The fetch failed. |
|
ProgressEvent |
The fetch succeeded. |
|
ProgressEvent |
The author specified timeout has passed before the fetch completed. |
|
ProgressEvent |
The fetch completed (success or failure). |
5 FormData
接口
typedef (File or USVString) FormDataEntryValue;
[Constructor(optional HTMLFormElement form),
Exposed=(Window,Worker)]
interface FormData {
void append(USVString name, USVString value);
void append(USVString name, Blob blobValue, optional USVString filename);
void delete(USVString name);
FormDataEntryValue? get(USVString name);
sequence getAll(USVString name);
boolean has(USVString name);
void set(USVString name, USVString value);
void set(USVString name, Blob blobValue, optional USVString filename);
iterable;
};
FormData
为了与其他算法进行交互,entry
FormData
- append(name, value)
- append(name, value, filename)
- delete(name)
- get(name)
- getAll(name)
- has(name)
- set(name, value)
- set(name, value, filename)
6 ProgressEvent
接口
[Constructor(DOMString type, optional ProgressEventInit eventInitDict),
Exposed=(Window,DedicatedWorker,SharedWorker)]
interface ProgressEvent : Event {
readonly attribute boolean lengthComputable;
readonly attribute unsigned long long loaded;
readonly attribute unsigned long long total;
};
dictionary ProgressEventInit : EventInit {
boolean lengthComputable = false;
unsigned long long loaded = 0;
unsigned long long total = 0;
};
Events
lengthComputable,loaded
6-1
使用 ProgressEvent接口 触发事件
触发进度事件。
6-2
建议使用的 ProgressEvent接口 事件名
本章节未标准化。
推荐的
type |
Description | Times | When |
---|---|---|---|
loadstart |
Progress has begun. | Once. | First. |
progress |
In progress. | Once or more. | After loadstart |
error |
Progression failed. | Zero or once (mutually exclusive). | After the
last progress |
abort |
Progression is terminated. | ||
timeout |
Progression is terminated due to preset time expiring. | ||
load |
Progression is successful. | ||
loadend |
Progress has stopped. | Once. | After one of error , abort , timeout load |
6-3 安全考虑
对于跨域请求,一些处理办法,CORS protocol定义了获取资源的标准。
6-4 用例
在下方
<<span class="hljs-name" style="margin: 0px; padding: 0px; font-family: "\\5FAE软雅黑"; position: relative; box-sizing: border-box; color: rgb(224, 108, 117);">title>Waiting for Magical Unicorns</<span class="hljs-name" style="margin: 0px; padding: 0px; font-family: "\\5FAE软雅黑"; position: relative; box-sizing: border-box; color: rgb(224, 108, 117);">title>
</<span class="hljs-name" style="margin: 0px; padding: 0px; font-family: "\\5FAE软雅黑"; position: relative; box-sizing: border-box; color: rgb(224, 108, 117);">progress>