写篇文章让自己清楚Ajax——(1)XMLHttpRequest是什么?

1,801 阅读7分钟

XMLHttpRequest的具体使用步骤会在get请求写法中进行展示,而post请求写法则会在post小点中展示。

XMLHttpRequest对象

XMLHttpRequest是浏览器内置构造函数,所有现代的浏览器都支持 XMLHttpRequest 对象。

XMLHttpRequest是什么

首先我们来看一下官方文档对这个对象的讲解:

》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

  • XMLHttpRequest简写XHR(xhr)
  • XMLHttpRequest对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。
  • 尽管名称如此,XMLHttpRequest 可以用于获取任何类型的数据,而不仅仅是 XML。它甚至支持 HTTP 以外的协议(包括 file:// 和 FTP),尽管可能受到更多出于安全等原因的限制。 》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

不通过js的http请求通常是通过form表单、script、link、img、video等标签完成。

总结一下:XMLHttpRequest对象功能

  • 发出http请求。
  • 用于获取任何类型数据。
  • 支持http甚至是ftp协议。 所以我们可以使用XMLHttpRequest对象向服务器发起请求,不再受限于原始的请求方式(form等标签)。

这里我展示一个简单的demo描述——阻止form提交请求并通过XMLHttpRequest对象来发起请求。

<form action="http://liyou.com:8080/login" method="POST" onsubmit='send(event)'> 
    <input name="name" type="text" placeholder="请输入名字">
    <input name="pwd" type="password" placeholder="请输入密码">
    <input type="submit" value="登录">
</form>
<script>
//这里编写了一个事件方法send(并且通过event的传参来实现对form标签默认的提交事件——http请求的阻止)
        function send(event) {
            console.log(event)
            event.preventDefault();
            let xhr = new XMLHttpRequest()
            xhr.open('post', 'http://juejin.com:8080/login')
            xhr.setRequestHeader('Context-type', 'application/x-www-form-urlencoded ');
            xhr.onload = function () {
                console.log(JSON.parse(xhr.responseText))
                console.log(xhr)            
            }
            xhr.send()
        }
</script>

这里的open方法中的第二个参数是无效的只是示例。

使用XMLHttpRequest

XMLHttpRequest 对象提供了对 HTTP 协议的完全的访问,所以初学者很容易遇到通过使用XMLHttpRequest实现发送请求的场景。

所以我们需要学习具体的使用,不求全知,但求能在面试官和同事面前牛皮吹得起。

从上面的示例中我们可以看的出是对post请求的实现。

先是get请求的XHR步骤:

XMLHttpRequest本身是一个构造函数,我通过这个构造函数构造一个对象出来,这个对象就是XMLHttpRequest实例:(我们通常使用xhr作为简写以及XMLHttpRequest实例变量名)

    let xhr = new XMLHttpRequest()

此时xhr作为XMLHttpRequest实例,继承了原型上封装好的方法,这些方法帮助我们去实现一个http请求,向服务器发送信息。 官方讲解的属性和方法集合

  1. open()——初始化一个请求
    xhr.open('参数一,填写http请求类型', 'url值(这里添加get请求的字符串参数格式————name=xxx&pwd=xxx)')

补充可选参数:

  • 参数三 async:布尔值,表示是否异步执行,默认true。浏览器大多不建议同步xhr执行。
  • 参数四 user:用户名用于认证用途;默认为null
  • 参数五 password:密码用于认证用途,默认为null

  1. setRequestHeader()——设置 HTTP 请求头
    xhr.setRequestHeader('请求头参数名', '对应的可选参数')
  • 该方法应该处于open和send方法之间,否则报错
  • 如果多次执行setRequestHeader方法,不会覆盖,而是自动整合为多个值的请求头。
  • 参数一header的大小写不敏感,字符正确即可。

  1. send()——发送请求

send方法应该在open和setRequestHeader等方法之后执行,建议放到最后执行

    xhr.send('这里get请求不用,只有post请求使用')

如果是异步请求(默认为异步请求),则此方法会在请求发送后立即返回;如果是同步请求,则此方法直到响应到达后才会返回。XMLHttpRequest.send() 方法接受一个可选的参数,其作为请求主体;如果请求方法是 GET 或者 HEAD,则应将请求主体设置为 null。


  1. load事件——xhr请求成功完成时触发 load是事件,事件由特定动作进行触发,我们通过给load注册一个回调函数,来提供对该事件的处理。
            xhr.onload = function () {
                console.log(JSON.parse(xhr.responseText))
                console.log(xhr)            
            }

我们最后来讲load事件中应该和可以使用哪些变量。这里展示完整get请求结构:

    let id = document.querySelector('#id').value;
    let xhr = new XMLHttpRequest()
    xhr.open('get','http://juejinlogin.com/mysql_find?id='+id)
    xhr.timeout = 5000;
    xhr.onload=()=>{
        console.log('接收到服务器响应');
        console.log(JSON.parse(xhr.responseText));
        //show(JSON.parse(xhr.responseText).user);
    }
    xhr.onerror=()=>{
        console.log('请求失败')
    }
    xhr.send(null);

差异讲解post请求XHR步骤:

基本的差异都是围绕请求差异本身上,即getpost在参数上的差异。

  • 差异一(请求方式)

open方法中参数一需要修改为post,表明初始化的请求为post请求

    xhr.open('post', 'url值(不加get请求的字符串参数后缀)')
  • 差异二(请求实体)

post将数据放入请求报文body,通过send方法。send()方法的参数写法:

//send(body)
    xhr.send("foo=bar&lorem=ipsum");
//官方例举的写法
// xhr.send('string');
// xhr.send(new Blob());
// xhr.send(new Int8Array());
// xhr.send({ form: 'data' });
// xhr.send(document);
  • 差异三(头部字段)

因为我们请求实体携带的数据类型并不是只要和符合官方的格式,服务器就能识别,还需要通过头部字段content-type进行配合告诉服务器请求报文实体中携带的数据应该怎么解析:

    xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
    xhr.send("foo=bar&lorem=ipsum");
    xhr.setRequestHeader('Content-type','application/json')//两种实体类型写法
    xhr.send(json字符串);

更多的参数和写法可以查看 写篇文章之计网——(6)HTTP Content-type

  • 完整post请求展示:
    let name = document.querySelector('#addname').value;
    let pwd = document.querySelector('#addpwd').value;
    let xhr = new XMLHttpRequest()
    xhr.open('post','http://juejinlogin.com/mysql_add')
    xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
    xhr.timeout = 5000;
    xhr.onload=()=>{
        console.log('接收到服务器响应');
        console.log(JSON.parse(xhr.responseText));
    }
    xhr.onerror=()=>{
        console.log('请求失败')
    }
    xhr.send(`name=${name}&password=${pwd}`);

如果body没有指定值,则默认值为 null,同时具体的数据写法要依据Content-type头部信息规范。(setRequestHeader方法设置)

客户端获取响应数据

承接load事件,我们已经确定服务器接收到请求并响应回来了。
实际上响应的是一个响应报文,我们需要获取里面的数据。
官方提供了三个属性接收数据,在load事件中我们可以放心使用。

  • 使用代码示例:
         //传输的字符串数据(文本),通常是JSON格式字符串,需要JSON方法解析成对象。   
            xhr.onload = function () {
                console.log(JSON.parse(xhr.responseText))
                console.log(JSON.parse(xhr.response))
                console.log(JSON.parse(xhr.responseXML))            
            }
  1. xhr.response

返回一个 ArrayBufferBlobDocument,或 DOMString,具体是哪种类型取决于 XMLHttpRequest.responseType的值。其中包含整个响应实体(response entity body)。

  1. xhr.responseText

我们在load回调函数中直接操作responseText属性就可以满足开发需求。

返回一个 DOMString,该 DOMString 包含对请求的响应,如果请求未成功或尚未发送,则返回 null

  1. xhr.responseXML

返回一个 Document,其中包含该请求的响应,如果请求未成功、尚未发送或不能被解析为 XML 或 HTML,则返回 null

通常情况下response为DOMString格式时和responseText的值是一样的,此时responseXML就会是null,因为response为DOMString时说明Document为unll。

  • 总结异同 》response和responseText默认值为空字符串""(可以尝试在send方法之前打印观察) 而responseXML默认是null

》response和responseText只有当请求成功时,才能拿到正确值。
而responseXML要在请求成功情况下返回数据能够被正确解析。

其他属性、方法和事件补充

这里我不会全部列举,太多反而看着心累,我们挑些常用的来讲。

timeout属性——超时

一个无符号长整型(unsigned long)数字,表示该请求的最大请求时间(毫秒),若超出该时间,请求会自动终止。老生常谈的知识了,我们上代码示例吧

    xhr.open('GET', '/server', true);

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

getResponseHeader和getAllResponseHeaders方法——响应头

getAllResponseHeaders以字符串的形式返回所有用CRLF分隔的响应头(返回所有),如果没有收到响应,则返回 null

getResponseHeader返回包含指定响应头的字符串(传参获取指定),如果响应尚未收到或响应中不存在该报头,则返回 null

    let headers = xhr.getAllResponseHeaders();
    let header = xhr.getAllResponseHeaders("Content-Type");

ontimeout事件——超时

超时本身就会停止了请求,从而触发请求停止的事件,但是仍然有单独的超时事件。

  xhr.ontimeout = function(e) {
    console.error("Timeout!!")
  }

onerror事件——失败

请求有成功就会有失败,当请求遇到错误时,将触发error 事件。

  xhr.onerror = function(e) {
    console.error("请求失败!!")
  }

下一篇我们讲解XMLHttpRequest的意义以及和Ajax的关系