AJAX - XMLHttpRequest - 接口

尽管名称如此, XMLHttpRequest 可以用于获取任何类型的数据, 而不仅仅是 XML, 它甚至支持 HTTP 以外的协议(包括file:// 和 FTP)

如果您的通信流程需要从服务器接收事件或消息数据, 可以选择SSE, 对于全双工的通信, WebSocket 则可能是更好的选择

一. 构造函数


XMLHttpRequest()

​ 该构造函数用于初始化一个 XMLHttpRequest 对象. 在调用下列任何其他方法之前, 必须先调用该构造函数, 或通过其他方式间接得到一个 XMLHttpRequest

/**
   * @name: 创建一个 XMLHttpRequest 对象
   * @return: XMLHttpRequest 对象
   */
var myRequest = new XMLHttpRequest();

二. 属性

此接口继承了 XMLHttpRequestEventTargetEventTarget 的属性。


1. readyState: 请求状态码(只读)

​ 返回一个 XMLHttpRequest 代理当前所处的状态. 一个 XHR 代理总是处于下列状态中的一个:

状态 描述
0 UNSENT 代理被创建, 但尚未调用 open() 方法
1 OPENED open() 方法已经被调用
2 HEADERS_RECEIVED send() 方法已经被调用, 并且头部和状态已经可获得
3 LOADING 下载中; responseText属性已经包含部分数据
4 DONE 下载操作已经完成, 这意味着数据传输已经彻底完成或失败。
// 示例 -- 状态为2的无法检测到?
var xhr = new XMLHttpRequest(); // readyState 为 0
xhr.open('GET', '/api', true); // readyState 为 1
xhr.onprogress = function () {
   // readyState 为 3
}

xhr.onload = function () {
    // readyState 为 4
}
xhr.send(null);

2. responseType: 响应类型(可写)

是一个枚举类型的属性, 返回响应数据的类型. 允许手动设置返回数据的类型. 默认为 'text' 类型(设置为空字符串时, 采用 'text' 类型)

当手动设置为一个特定的类型时, 你需要确保服务器所返回的类型和你所设置的返回值类型是兼容的.

当服务器返回的返回值类型 和 所设置的响应类型不兼容时, 服务器返回的数据变成了 null, 即使服务器返回了数据

给一个同步模式的请求, 设置 responseType 会抛出一个 InvalidAccessError 的异常

要在 open() 初始化请求之后调用, 并且要在调用 send() 发送请求到服务器之前调用

描述
"" 与设置为 "text" 相同, 是默认类型 (实际上是 DOMString(相当于String) )
"arraybuffer" 是一个包含二进制数据的 JavaScript ArrayBuffer
"blob" 是一个包含二进制数据的 Blob 对象
"document" 是一个HTML DocumentXML XMLDocument, 这取决于接受到的数据的 MIME 类型
"json" 是一个 JavaScript 对象. 这个对象是通过将接受到的数据类型视为 JSON 解析得到的
"text" 是包含在 DOMString 对象中的文本
"moz-chunked-arraybuffer"(不是标准的) "arraybuffer"相似,但是数据会被接收到一个流中。使用此响应类型时,响应中的值仅在 progress 事件的处理程序中可用,并且只包含上一次响应 progress 事件以后收到的数据,而不是自请求发送以来收到的所有数据。
"ms-stream"(不是标准的) response 是下载流的一部分;此响应类型仅允许下载请求,并且仅受Internet Explorer支持。

3. response: 响应数据(只读)

返回的类型可以是 ArrayBufferBlobDocument 、 JavaScript ObjectDOMString 。取决于 responseType 属性设置的值

响应的类型如下所示(与responseType一致):

描述
"" 与设置为 "text" 相同, 是默认类型 (实际上是 DOMString(相当于String) )
"arraybuffer" 是一个包含二进制数据的 JavaScript ArrayBuffer
"blob" 是一个包含二进制数据的 Blob 对象
"document" 是一个HTML DocumentXML XMLDocument, 这取决于接受到的数据的 MIME 类型
"json" 是一个 JavaScript 对象. 这个对象是通过将接受到的数据类型视为 JSON 解析得到的
"text" 是包含在 DOMString 对象中的文本
"moz-chunked-arraybuffer"(不是标准的) "arraybuffer"相似,但是数据会被接收到一个流中。使用此响应类型时,响应中的值仅在 progress 事件的处理程序中可用,并且只包含上一次响应 progress 事件以后收到的数据,而不是自请求发送以来收到的所有数据。
"ms-stream"(不是标准的) response 是下载流的一部分;此响应类型仅允许下载请求,并且仅受Internet Explorer支持。
let xhr = new XMLHttpRequest();
      xhr.responseType = "arraybuffer";
      xhr.open("GET", "/url/api/system/system-dic/listAll");
      xhr.onload = function(e) {
        /*
            onabort: null
            onerror: null
            onload: ƒ (e)
            onloadend: null
            onloadstart: null
            onprogress: null
            onreadystatechange: null
            ontimeout: null
            readyState: 4
            response: ArrayBuffer(65) {}
            responseText: (...)
            responseType: "arraybuffer"
            responseURL: "http://localhost:8080/url/api/system/system-dic/listAll"
            responseXML: (...)
            status: 200
            statusText: "OK"
            timeout: 0
            upload: XMLHttpRequestUpload {onloadstart: null, onprogress: null, onabort: null, onerror: null, onload: null, …}
            withCredentials: false
          */
        console.log(xhr);
      };
      xhr.send(null);

4. responseText: 请求响应(DOMString)(只读)

处理的是 DOMString 数据, 是返回的纯文本的值

当responseType为"text" 或者 ""时, 此属性才会存储着后端返回的数据

// 当 xhr.responseType = "json",  
// xhr.responseText: 报错信息(未能从“XMLHttpRequest”读取“responseText”属性:仅当对象的“responseType”为“”或“text”(为“json”)时才可访问该值。)

// 当 xhr.responseType="text" 或为默认值 "",
// xhr.responseText: {"msg":"您不允许访问该资源,请重新登录","ret":401}

5. responseXML: 请求响应(Document)(只读)

处理的是Document数据, 如果请求未成功, 尚未发送, 或者检索的数据无法正确解析为 XML 或 HTML, 则为null

默认是当作“text / xml” 来解析。当 responseType 设置为 “document” 并且请求已异步执行时,响应将被当作 “text / html” 来解析。responseXML 对于任何其他类型的数据以及 data: URLs 为 null

// 当 xhr.responseXML = "json",  
// xhr.responseXML: 报错信息(无法从“XMLHttpRequest”读取“responseXML”属性:仅当对象的“responseType”为“”或“document”(为“json”)时,才可访问该值。)

// 当 xhr.responseType="document",
// xhr.responseXML: null(解析错误)

6. responseURL: 响应序列化URL(只读)

返回响应的序列化URL, 如果URL为空则返回空字符串. 如果URL有锚点, 则位于URL#后面的内容会被删除. 如果URL有重定向, responseURL 的值回事经过多次重定向后的最终URL

xhr.responseURL = 'http://localhost:8080/url/api/system/system-dic/listAll'

7. status: 响应状态码(只读)

返回响应中的数字状态码, 在请求完成前, status的值为0. 值得注意的是, 如果 XMLHttpRequest 出错, 浏览器返回的 status 也为0

status码是标准的 HTTP status codes. 如果服务器响应中没有明确指定 status 码, XMLHttpRequest.status 将会默认为200

var xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.status);

xhr.open('GET', '/server', true);
console.log('OPENED', xhr.status);

xhr.onprogress = function () {
  console.log('LOADING', xhr.status);
};

xhr.onload = function () {
  console.log('DONE', xhr.status);
};

xhr.send(null);

/**
 * 输出如下:
 *
 * UNSENT(未发送) 0
 * OPENED(已打开) 0
 * LOADING(载入中) 200
 * DONE(完成) 200
 */

8. statusText: 响应状态(DOMString)(只读)

不同于 status 属性的区别, 这个属性包含了返回状态对应的文本信息, 例如 "OK" 或是 "Not Found".

如果服务器未明确指定一个状态文本信息, 则 statusText 的值将会被自动赋值为 "OK"

var xhr = new XMLHttpRequest();
console.log('0 UNSENT', xhr.statusText);

xhr.open('GET', '/server', true);
console.log('1 OPENED', xhr.statusText);

xhr.onprogress = function () {
  console.log('3 LOADING', xhr.statusText);
};

xhr.onload = function () {
  console.log('4 DONE', xhr.statusText);
};

xhr.send(null);

/**
 * 输出如下:
 *
 * 0 UNSENT
 * 1 OPENED
 * 3 LOADING OK
 * 4 DONE OK
 */

9. upload: 上传过程(只读)

**返回一个 XMLHttpRequestUpload 对象, 用来表示上传的进度. **

这个对象类似于 XMLHttpRequestUpload, 专门用来表示上传过程, 可用来实现上传过程中的相关事件

事件 相应属性的信息类型
onloadstart 获取开始
onprogress 数据传输进行中
onabort 获取操作终止
onerror 获取失败
onload 获取成功
ontimeout 获取操作在用户规定的时间内未完成
onloadend 获取完成(不论成功与否)

10. timeout: 超时时间(可读写)

表示请求的最大请求时间(毫秒), 若超出该时间, 则请求会自动结束

是一个无符号长整型数, 默认值为0, 意味着没有超时, 当超时发生, timeout 事件将会被触发

在 IE 中, 超时属性可能只能在调用 open() 方法之后且在调用 send() 方法之前设置

var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);

xhr.timeout = 2000; // 超时时间,单位是毫秒

xhr.onload = function () {
  // 请求完成。在此进行处理。
  // 超时不会触发这个事件  
};

xhr.ontimeout = function (e) {
  // XMLHttpRequest 超时。在此做某事。
};

xhr.send(null);

11. withCredentials: 跨域请求是否带有授权信息(cookie 或 授权 header 头)

是一个布尔值, 它指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。

**注意: 在同一个站点下(就是没有产生跨域)使用withCredentials 属性是无效的, 这个指示也会被用做响应中 cookies 被忽视的标示. **

如果在发送来自其他域的XMLHttpRequest请求之前,未设置withCredentials 为true,那么就不能为它自己的域设置cookie值。而通过设置withCredentials 为true获得的第三方cookies,将会依旧享受同源策略,因此不能被通过document.cookie或者从头部相应请求的脚本等访问。

注意: 永远不会影响到同源请求

注意: 不同域下的XmlHttpRequest 响应,不论其Access-Control- header 设置什么值,都无法为它自身站点设置cookie值,除非它在请求之前将withCredentials 设为true。

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null);

12. 非标准属性

属性 描述
channel nsIChannel,对象在执行请求时使用的通道。
mozAnon 一个布尔值,如果为真,请求将在没有cookie和身份验证header头的情况下发送。
mozSystem 一个布尔值,如果为真,则在请求时不会强制执行同源策略。
mozBackgroundRequest 一个布尔值,它指示对象是否是后台服务器端的请求。

三. 方法


1. open(): 初始化一个请求.

注意: 为已激活的请求调用此方法( open() 已被调用) 相当于调用 abort()

/**
     * @name: 初始化一个请求
     * @param {String} 要使用的 HTTP 方法(GET, POST, PUT...), 对于非 HTTP(S) URL 被忽略
     * @param {String} 要发送请求的URL
     * @param {Boolean?} 请求模式, true(默认值, 异步模式) | false(同步模式)
     * @param {any?} 可选的用户名用于认证用途;默认为null。
     * @param {any?} 可选的密码用于认证用途,默认为null。
     */
xhrReq.open(method, url, async?, user?, password?);

2. setResponseHeader(): 设置 HTTP 请求头的值

此方法必须在 open() 和 send() 之间调用. 如果多次对同一请求头赋值, 只会生成一个合并了多个值得请求头

自定义一些 header 属性进行跨域请求时, 可能会遇到 "not allowed by Access-Control-Allow-Headers in preflight response" 你可能需要在你的服务器端设置 "Access-Control-Allow-Headers

/**
    * @name: 设置 HTTP 请求头的值
    * @param: {String} 属性的名称
    * @param: {String} 属性的值
**/
xhr.setRequestHeader(header, value);

3. getResponseHeader(): 返回指定响应头的字符串

如果响应尚未收到或响应中不存在该响应, 则返回 null

必须要指定响应头名称, 也就是必须要有一个参数, 可通过 getAllResponseHeaders() 获取全部可获取的响应头

如果在返回头中有多个一样的名称, 那么返回的值就会使用逗号和空号分隔的字符串. 搜索标题名称是不区分大小写的。

/**
    * @name: 获取 HTTP 请求头的值
    * @param: {String} 响应头名称
    * @return: 指定响应头内容, 如果响应尚未收到, 或者响应中不存在, 则返回 null
**/
xhr.getRequestHeader(name);

4. getAllResponseHeaders(): 返回所有用 CRLF 分隔的响应头

注意: 对于复合请求 ( multipart requests ),这个方法返回当前请求的头部,而不是最初的请求的头部。

/**
    * @name: 获取 HTTP 请求头的值
    * @return: 返回所有的响应头,以 CRLF 分割的字符串,或者 null 如果没有收到任何响应。
**/
xhr.getAllResponseHeaders();

/*
返回示例:
cache-control: no-cache, no-store, max-age=0, must-revalidate
connection: close
content-type: application/json;charset=UTF-8
date: Thu, 12 Dec 2019 14:53:35 GMT
expires: 0
pragma: no-cache
transfer-encoding: chunked
vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
x-content-type-options: nosniff
x-powered-by: Express
x-xss-protection: 1; mode=block 
*/

5. send(): 发送请求

用于发送 HTTP 请求, 如果是异步请求(默认为异步请求), 则此方法会在请求发送后立即返回;如果是同步请求,则此方法直到响应到达后才会返回。

/**
    * @name: 发送请求
    * @param: {any?} 请求方法为 GET 或者 HEAD 时, 应该讲请求主题设置为 null. 请求方法为其他方法时, 其参数将作为请求主体发送至服务器
**/
xhr.send(data?);
/*
数据类型: 
1. ArrayBuffer
2. ArrayBufferView
3. Blob
4. Document
5. DOMString(也就是String)
6. FormData
注意: 
应该在发送请求即调用 send() 方法之前使用 setRequestHeader() 方法设置 Content-Type 头部来指定请求主体的数据流的 MIME 类型
*/

6. abort(): 中止请求

如果请求已被发出, abort() 方法将终止该请求. 当一个请求被终止, 它的readyStete 属性将被置为0

/**
    * @name: 中止请求(会回到 open()[打开请求状态之前] )
**/
xhr.abort();

7. overrideMimeType():重写由服务器返回的 MIME 类型

指定一个 MIME 类型用于替代服务器指定的类型, 使服务器响应信息中传输的数据按照该指定 MIME 类型处理. 例如强制使流方式处理为"text/xml"类型处理时会被使用到,即使服务器在响应头中并没有这样指定.

此方法必须在 send 方法之前调用才有效

如果服务器没有指定一个Content-Type 头, XMLHttpRequest 默认MIME类型为"text/xml". 如果接受的数据不是有效的XML,将会出现格”格式不正确“的错误。你能够通过调用 overrideMimeType() 指定各种类型来避免这种情况。

/**
    * @name: 重写响应 MIME 类型
    * @param: {MIME类型} 指定具体的 MIME 类型去代替服务器指定的 MIME 类型. 如果服务器没有指定类型, 那么默认为 "text/xml"
**/
xhr.overrideMimeType(mimeType)

8. 非标准方法

方法 描述
init() 在 C++ 代码中初始化一个 XHR 对象。
openRequest() 初始化一个请求. 这个方法用于本地代码; 如果用JavaScript 代码来初始化请求,使用 open()代替. 可参考 open() 的文档。
sendAsBinary() send() 方法的变体,用来发送二进制数据。

四. 事件

**下列事件可在 XMLHttpRequest 对象中触发, 同时大部分事件(具体见 upload属性)也可在 xhr.upload 返回 XMLHttpRequestUpload(代表上传过程)中调用 **


1. readystatechange: 当 readyState 状态变化时调用

会在 XMLHttpRequest 的 readyState 属性发生改变时调用(不该用于同步的 requests 对象

xhr.onreadystatechange = function () {
  if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
    // 在这里说明调用成功了
    console.log(xhr.responseText)
  }
}

2. load: 请求成功完成时调用

xhr.addEventListener('load', function(e) {
    // 在这里说明调用成功了, xhr.readyState === 4
})

3. loadstart: 开始传送数据时触发

开始传送数据时触发, 只会触发一次

xhr.addEventListener("loadstart", function(e) {
  // 在 response 状态为1(调用了 send() 方法, 已经开始建立连接, 但是 response 还是为1
  console.log("开始传送数据时", xhr.response);
});

4. progress: 下载和上传的传输周期触发

周期性触发, 可用来实现进度条(具体发送数据在 event 中)


xhr.addEventListener("progress", function(e) {
   // e.loaded: 在周期性调用中接受到了多少信息
   // e.total: 该请求一共多少信息 
   console.log("周期性发送数据", e);
});

5. loadend: 请求结束时触发

当请求结束时触发, 无论请求成功(load) 还是失败(abort 或 error)

需要注意的是,没有方法可以确切的知道 loadend 事件接收到的信息是来自何种条件引起的操作终止;但是你可以在所有传输结束的时候使用这个事件处理。

xhr.addEventListener("loadend", function(e) {
   // 无论请求成功还是失败都会调用, 但是这里不是很好区分成功原因 或 失败原因吧
   console.log("请求结束", xhr);
});

6. abort: 当请求停止时触发

当请求终止时 abort 事件被触发, 例如调用了 abort() 方法

xhr.addEventListener("abort", function(e) {
   console.log("请求停止", xhr);
});

7. timeout: 请求超时时触发

当请求时间超出预定时间而终止请求时发出

xhr.addEventListener("timeout", function(e) {
   console.log("请求超时", xhr);
});

8. error: 请求错误时触发

xhr.addEventListener("error", function(e) {
   console.log("请求错误", xhr);
});

参考文档

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  •   2005 年,Jesse James Garrett 发表了一篇在线文章,题为“Ajax: A new App...
    霜天晓阅读 885评论 0 1
  • 简介 AJAX是Asynchronous JavaScript and XML的缩写,指的是通过JavaScrip...
    oWSQo阅读 2,277评论 0 4
  • Ajax和XMLHttpRequest 我们通常将Ajax等同于XMLHttpRequest,但细究起来它们两个是...
    changxiaonan阅读 2,229评论 0 2
  • 浏览器与服务器之间,采用HTTP协议通信。用户在浏览器地址栏键入一个网址,或者通过网页表单向服务器提交内容,这时浏...
    许先生__阅读 494评论 1 2
  • 公认的“性趣”识别器点击上方关注“百分之三”每天有情、有趣、有料! ​话说三国,合久必分,分久必合。谈的恋爱不多,...
    巨梨App阅读 601评论 0 0