XMLHttpRequest剖析

1.什么是XMLHttpRequest?

首先XMLHttpRequest是一个构造函数,是位于Window对象上的一个构造函数。

所以要使用需要通过new命令创建一个实例。

const xhr = new XMLHttpRequest();

由于位于Window对象,所以实例化的xhr对象其实就是一个浏览器内置的对象。

它提供了对http协议的完全的访问,用于JS进行http请求和http响应。

2.兼容性

几乎所有的主流浏览器都支持,IE需要通过下面的办法兼容

new ActiveXObject("Microsoft.XMLHTTP")

3.发展历史

XMLHttpRequest有两个阶段,一个是Level1,一个是Leve2

level1的缺点:

  • 受同源策略(Same Origin Policy)影响, 不能发送跨域请求
  • 不能发送二进制(音频,视频,图片等)文件,只能发送文本
  • 发送和接收数据时,没有实时进度信息,只能判断是否完成

level2解决了以上缺点,并添加了新功能:

  • 只要服务器允许,可以进行跨域访问
  • 可以发送和获取二进制数据(音频,视频,图片等都是二进制文件)
  • 可以获取请求发送数据的实时进度信息
  • 新增FormData数据,可以发送表单数据(multipart/formdata)
  • 可以设置过时时间timeout

4.只读属性

1.readyState --HTTP 请求的状态.

从对象实例化为0开始到结束为4,依次递增。

状态 名称 描述
0 UNSENT 初始化。new了实例或者已经被abort()方法重置
1 OPENED 调用了open方法,但是还未调用send方法。请求还未发送。
2 HEADERS_RECEIVED web服务器接收到请求头,send发送成功。未收到响应。
3 LOADING 响应头已经接收。响应体开始接收,未完成。
4 DONE 响应接收完成。

每次状态改变都会触发onreadystatechange事件。

LOADING状态可能会触发多次,因为每接收一个数据包就会触发一次。

2.status--http请求响应中~的状态码

进入响应前和响应失败都是0;响应中如果未特殊指定,都为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
 */

3. statusText -- http响应中~的状态名称

例如:xhr.statusText --- OK 

4. response--返回响应(XHR2)

可以和responseType一起取代原来的responseText, responseXML等;

5.可写属性

1.responseType --- 指定响应返回的数据格式(XHR2)

  • "": 默认。 返回字符串
  • "text": 返回字符串。
  • "arraybuffer": 返回ArrayBuffer类型的数据(二进制)。
  • "blob": 返回Blob数据。
  • "document": 返回XML文档。
  • "json": 返回JSON数据。
xhr.responseType = ‘json‘;

2.timeout--设置请求超时时间

默认0,表示不设置请求超时。

只能用于异步请求,同步请求不允许。

3.withCredentials--携带验证信息

默认false;

同域请求时,浏览器会自动将cookie添加到请求头中,但是跨域请求不会。

因为CORS规定,跨域时,不允许携带任何认证信息,除非withCredentials=true;

首先,为了能够跨域,服务器端需要设置

Access-Control-Allow-Origin: *// 或者具体的域名

如果请求需要认证信息,浏览器端需要设置:

xhr.withCredentials = true

服务器端需要设置

Access-Control-Allow-Origin: //具体的origin,一定不能设置成*
Access-Control-Allow-Credentials: true

6.方法

1.open(method, url [, async, username, password])方法

初始化请求参数

method: 请求方式主要有GET,POST,也可以是HEAD(请求资源的头部信息,和GET返回的头部一样)---CORS安全

url: 请求路由

async: 默认true,异步请求。为false时,同步, 已被废弃deprecated。

基本都用异步请求。同步请求几乎不用,一是因为会出现阻塞,网页挂起的情况;二是不能使用timeout,不能进行跨域,也没有进度信息。

const xhr = new XMLHttpRequest();
xhr.open("POST", url, true); // 异步
xhr.send();
// readyState === 1 异步请求send立即返回

const xhr = new XMLHttpRequest();
xhr.open("POST", url, false); // 同步
xhr.send();
// readyState === 4 同步等所有的进程结束再返回

username,password: 认证权限

2. setRequestHeader(name, value)

只能在open和send之间调用。既可以设置系统默认的一些头部信息(如ContentType),也可以设置自定义的头部信息(‘X-USER’)。

一旦设置,就无法撤销。设置同样的name,也是append,而不会覆盖。

var client = new XMLHttpRequest();
client.open(‘GET‘, ‘demo.cgi‘);
client.setRequestHeader(‘X-Test‘, ‘one‘); // 自定义请求头
client.setRequestHeader(‘X-Test‘, ‘two‘);  // 自定义请求头
client.send();
// X-TEST: one, two

name: 请求头的名称。忽略大小写。

有些请求头只能由浏览器控制,用户不能操作。否则  Refused to set unsafe header "..."

`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`
`TE`
`Trailer`
`Transfer-Encoding`
`Upgrade`
`Via`

用户可以操作的请求头有:

Content-Type: 设置发送的数据类型,即send(body)中请求体的类型。以下全部为POST请求

  • "multipart/formdata; boundry=something": 当传递FormData类型时,默认是该类型。

// 示例: multipart/form-data; boundary=----WebKitFormBoundary2OgAPgMEOp8S1XFR

...
data = new FormData();
data.append(‘name‘, ‘lyra‘);
data.append(‘age‘,18);
xhr.send(data);
// 还可以从网页中获取表单的值
<form id="form">
<input type=‘text‘ name="age" value="" /><!--必须有name-->
</form>
data = new FormData(formData);
data.append(‘name‘,‘lyra‘);
xhr.send(data);
// 还可以上传文件等二进制文件
<body>
    <button onclick="loadJSONDoc()">Get JSON</button>
    <form id="form">
        <label for="image">上传图片</label>
        <input id="file" type=‘file‘ name="image" accept="image/png,image/jpeg" multiple />
    </form>
    <script>
        var xhr;
        function loadJSONDoc() {
            xhr = null;
            if (window.XMLHttpRequest) {// code for Firefox, Chrome, etc.
                xhr = new XMLHttpRequest();
                console.log(xhr.readyState); // 0
            } else if (window.ActiveXObject) {// code for IE
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            xhr.onreadystatechange = function() {
                // 0,1,2,3,4
                console.log(xhr.readyState)
            }
            if (xhr != null) {
                let data = null;
                const fileDOM = document.querySelector(‘input‘);
                const formData = new FormData();
                const files = fileDOM.files; // 元素的files属性获取文件列表
                for(let file of files) {
                    formData.append("file", file);
                }
                data = formData;
                xhr.open("POST", ‘/postdata‘, true); // 1
                xhr.send(data);
            }
        }
    </script>
</body>
  • "application/x-www-form-urlencoded;charset=UTF-8": 当传递URLSearchParams类型时,默认是该类型。
// 直接通过URLSearchParams对象
...
data = new URLSearchParams(‘name=5‘);
xhr.send(data);
// 还可以通过URL对象的searchParams属性
...
data = (new URL(‘http://www.dd.com?name=5‘)).searchParams;
xhr.send(data);

//PS: 当form表单设置method="POST"时,系统默认的请求头Content-Type的值是:
application/x-www-form-urlencoded
// 当method不设置,或者设为“GET”时,为url传参,传参形式是:
?name=value&name1=value1...
//没有Content-Type请求头
  • "text/html;charset=UTF-8":  当传递的数据为document类型时,默认是该类型。
data = document;
xhr.send(data);
  • "text/plain; charset=UTF-8": 当传递的数据是对象,数字,字符串,布尔值时,默认都是该类型。

??//单独的传"name=lyra"属于字符串,不是URLSearchParams对象。

data = {a: 1};
//data = "22";
//data = 22;
//data = true
xhr.send(data);
  • "application/json; charset=UTF-8": 浏览器不会默认该类型,需要手动添加。传参数据需要JSON.stringify()处理。
data = JSON.stringify({a: 0});
xhr.setRequestHeader(‘Content-Type‘,‘application/json;charset=UTF-8‘);xhr.send(data);

3.send([body])

发送http请求。

如果是GET方法,没有请求体body或者传null。

POST方法需要传请求体body。

4.getAllResponseHeaders()

获取除了Set-Cookie和Set-Cookie2之外的所有响应头信息。

并且每个头信息单独占一行。例如:

Cache-Control: max-age=31536000
Content-Length: 4260
Content-Type: image/png
Date: Sat, 08 Sep 2012 16:53:16 GMT

如上所示,返回的响应头信息,每一行都是以(‘\r\n‘)分割,并且该规则所有操作系统都一样。

name和value之间以冒号+空格隔开": " ,是一个固定的规范。

所以想要获取一个name,value是对象的形式,可以如下操作:

xhr.onreadystatechange = function() { // 只有在readyState >=3 的时候,才能获取正确的结果。
    if (xhr.readyState ===3 || xhr.readyState === 4) {
        const allHeaders = xhr.getAllResponseHeaders();
        // 注意需要清空两头的"\r\n",否则会多出"":undefined
        const resultObj = allHeaders.trim().split("\r\n").reduce((memo, next) => {
            let [name, value] = next.split(": ");
            if (memo[name]) { // 如果请求头重复
                memo[name] = `${memo[name]}; ${value}`;
            } else {
                memo[name] = value;
            }
            return memo
        }, {})
        console.log(resultObj);
    }
}

5.getResponseHeader(name)

获取特定名称的响应头信息,除了Set-Cookie和Set-Cookie2

xhr.getResponseHeader(‘Content-Type‘);

6.abort()

终止请求。xhr.abort();

7. XHR相关事件

1.onreadystatechange:

当readyState状态改变时触发;但重置时,即变为0,不触发。

2. onloadstart:

当掉用send()方法时,触发该事件;

3. onprogress:

分为文件上传进度: xhr.upload.onprogress send()之后,readyState=2之前触发

下载进度 xhr.onprogress readyState=3触发

4.onload:

readyState = 4触发

5. onloadend:

请求结束(成功或者失败)触发

6.onabort:

调用xhr.abort()触发

7.onerror:

请求失败触发;网络问题或者请求路由有误。

8.ontimeout:

从onloadstart开始,超过设置的timeout时间触发;timeout不为0。

8.xhr的上传对象

xhr上有个upload属性,可以用来描述文件上传的状态。

它有除了onreadystatechange之外,xhr有的其他7个事件。

原文地址:https://www.cnblogs.com/lyraLee/p/11580767.html

时间: 2024-10-07 22:51:32

XMLHttpRequest剖析的相关文章

javascript XMLHttpRequest对象全面剖析(转)

一. 引言 异步JavaScript与XML(AJAX)是一个专用术语,用于实现在客户端脚本与服务器之间的数据交互过程.这一技术的优点在于,它向开发者提供了一种从Web服务器检索数据而不必把用户当前正在观察的页面回馈给服务器.与现代浏览器的通过存取浏览器DOM结构的编程代码(JavaScript)动态地改变被显示内容的支持相配合,AJAX让开发者在浏览器端更新被显示的HTML内容而不必刷新页面.换句话说,AJAX可以使基于浏览器的应用程序更具交互性而且更类似传统型桌面应用程序. Google的G

javascript XMLHttpRequest对象全面剖析

转载:http://www.jb51.net/article/23175.htm 一. 引言 异步JavaScript与XML(AJAX)是一个专用术语,用于实现在客户端脚本与服务器之间的数据交互过程.这一技术的优点在于,它向开发者提供了一种从Web服务器检索数据而不必把用户当前正在观察的页面回馈给服务器.与现代浏览器的通过存取浏览器DOM结构的编程代码(JavaScript)动态地改变被显示内容的支持相配合,AJAX让开发者在浏览器端更新被显示的HTML内容而不必刷新页面.换句话说,AJAX可

JS魔法堂:jsDeferred源码剖析

一.前言 最近在研究Promises/A+规范及实现,而Promise/A+规范的制定则很大程度地参考了由日本geek cho45发起的jsDeferred项目(<JavaScript框架设计>提供该资讯,再次感谢),追本溯源地了解jsDeferred是十分有必要的,并且当你看过官网(http://cho45.stfuawsc.com/jsdeferred/)的新手引导后就会有种不好好学学就太可惜的感觉了,而只看API和使用指南是无法满足我对它的好奇心的,通过解读源码读透它的设计思想才是根本.

下载-深入浅出Netty源码剖析、Netty实战高性能分布式RPC、NIO+Netty5各种RPC架构实战演练三部曲视频教程

下载-深入浅出Netty源码剖析.Netty实战高性能分布式RPC.NIO+Netty5各种RPC架构实战演练三部曲视频教程 第一部分:入浅出Netty源码剖析 第二部分:Netty实战高性能分布式RPC 第三部分:NIO+Netty5各种RPC架构实战演练

深入剖析Java中的装箱和拆箱

阅读目录 一.什么是装箱?什么是拆箱?二.装箱和拆箱是如何实现的三.面试中相关的问题 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱.拆箱相关的问题. 回到顶部 一.什么是装箱?什么是拆箱? 我们知道 Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Java SE5之前,如果要生成

.Net WinForm 控件键盘消息处理剖析

在WinForm控件上我们可以看到很多关于键盘消息处理的方法,比如OnKeyDown, OnKeyPress, ProcessCmdKey, ProcessDialogKey,IsInputKey等等,那么这些方法是如何被组织的,每一个方法的具体含义又是什么哪?Win32的键盘消息又是如何到达控件上的这些方法的,本文将着重阐述这些问题,对.Net WinForm控件的键盘消息处理过程进行剖析.  1.      WinForm消息循环 大家都知道WinForm也是依赖于底层的消息机制的,通常我们

HTTPS 原理剖析与项目场景

最近手头有两个项目,XX导航和XX产业平台,都需要使用HTTPS协议,因此,这次对HTTPS协议做一次整理与分享. 为什么使用HTTPS HTTP 协议,本身是明文传输的,没有经过任何安全处理.那么这个时候就很容易在传输过程中被中间者窃听.篡改.冒充等风险.这里提到的中间者主要指一些网络节点,是用户数据在浏览器和服务器中间传输必须要经过的节点,比如 WIFI 热点,路由器,防火墙,反向代理,缓存服务器等. HTTP 协议,中间者可以窃听隐私,使用户的敏感数据暴露无遗:篡改网页,例如往页面插的广告

深入剖析php执行原理(4):函数的调用

本章开始研究php中函数的调用和执行,先来看函数调用语句是如何被编译的. 我们前面的章节弄明白了函数体会被编译生成哪些zend_op指令,本章会研究函数调用语句会生成哪些zend_op指,等后面的章节再根据这些op指令,来剖析php运行时的细节. 源码依然取自php5.3.29. 函数调用 回顾之前用的php代码示例: <?php function foo($arg1) { print($arg1); } $bar = 'hello php'; foo($bar); 在函数编译一章里已经分析过,

MapReduce/Hbase进阶提升(原理剖析、实战演练)

什么是MapReduce? MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算.概念"Map(映射)"和"Reduce(归约)",和他们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性.他极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上. 当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一