前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >AJAX 与跨域通信(一):AJAX

AJAX 与跨域通信(一):AJAX

作者头像
Chor
发布2019-11-08 10:11:15
8320
发布2019-11-08 10:11:15
举报
文章被收录于专栏:前端之旅前端之旅
1.AJAX 解决了什么问题?

在远古时代,如果浏览器需要从服务器请求资源,其交互模式为 “客户端发出请求 -> 服务端接收请求并返回相应 HTML 文档 -> 页面刷新,客户端加载新的 HTML文档”,很显然,在这种情况下,即使只是为了更新部分数据,我们也不得不重新加载整个重绘的页面。而 AJAX 的出现解决了这个问题。

AJAX 即异步 JavaScript 和 XML,它可以在不重新加载整个网页的情况下,对网页的某部分进行异步更新。

2.XMLHttpRequest 对象

AJAX 的核心实现依靠的是浏览器提供的 XMLHttpRequest 对象。可以看作是一个构造函数,由此我们可以通过 const xhr = new XMLHttpRequest() 创建一个 XML 对象的实例,该实例有以下方法:

  • open():准备启动一个 AJAX 请求;
  • setRequestHeader():设置请求头部信息;
  • send():发送 AJAX 请求;
  • getResponseHeader(): 获得响应头部信息;
  • getAllResponseHeader():获得一个包含所有头部信息的长字符串;
  • abort():取消异步请求;

以及以下属性:

  • responseText:包含响应主体返回文本;
  • responseXML:如果响应的内容类型是 text/xml 或 application/xml,该属性将保存包含着相应数据的 XML DOM文档;
  • status:响应的 HTTP 状态;
  • statusText:HTTP 状态的说明;
  • readyState:表示“请求”/“响应”过程的当前活动阶段

3.AJAX 请求

3.1 创建 XML 对象的实例:
代码语言:javascript
复制
const xhr = new XMLHttpRequest();
3.2 准备请求
代码语言:javascript
复制
xhr.open('get','demo.php?name=Sam&job=coder');

open() 方法接收三个参数:请求方式,请求 URL 地址和是否为异步请求的布尔值。

  • 请求方式:有 GET 和 POST 两种,GET 请求用于向服务器拿取数据,我们可以像示例代码中那样给 URL 加上查询参数,即 ?name=Sam&job=coder,表示要查询的特定资源;POST 请求用于向服务器发送要保存的数据,数据存放的位置通过 send() 方法的参数来指定。那么,对于 GET 请求,send() 方法是否可以不传递参数呢?——不可以,应该传递 null
  • 请求 URL:可以是相对路径和绝对路径
  • 是否为异步请求:true 为异步,false 为同步。
3.3 设置请求头
代码语言:javascript
复制
xhr.setRequestHeader('Header','Value')

每个 HTTP 请求和响应都会带有相应的头部信息,包含一些与数据、收发者网络环境与状态等相关信息。 默认情况下,当发送 AJAX 请求时,会附带以下头部信息:

  • Accept:浏览器能够处理的内容类型;
  • Accept-Charset: 浏览器能够显示的字符集;
  • Accept-Encoding:浏览器能够处理的压缩编码;
  • Accept-Language:浏览器当前设置的语言;
  • Connection:浏览器与服务器之间连接的类型;
  • Cookie:当前页面设置的任何Cookie;
  • Host:发出请求的页面所在的域;
  • Referer:发出请求的页面URI;
  • User-Agent:浏览器的用户代理字符串;

另外,我们还可以通过 setRequestHeader() 方法来设置请求头信息。该函数接受两个参数:头部字段(部分默认的或者自定义的)的名称和头部字段的值。

这个方法要在 open()send() 之间调用

3.4 发送请求
代码语言:javascript
复制
xhr.send(null)
// 或者 
xhr.send(data_holder)
3.5 处理响应

目前为止,我们只是发送了请求,还没有针对服务器的响应结果做出一些处理。比方说,响应成功了怎么怎么样,响应失败了怎么怎么样。但是怎么知道是成功还是失败呢?这里就用到前面讲过的 xhr.status 属性,状态码可分为五大类:

状态码

范围

分类

1XX

100-101

信息提示

2XX

200-206

成功

3XX

300-305

重定向

4XX

400-415

客户端错误

5XX

500-505

服务器错误

当然还有具体的分类,这里不展开讲。 那么,根据 xhr.status 这个响应结果,我们就可以进行相应处理了:

代码语言:javascript
复制
...
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText)
} else {
    alert("Request was unsuccessful: " + xhr.status)
}

这么写对于同步请求(我们前面设置 open() 时第三个参数是 false)来说当然没问题 —— 因为是同步的,所以一定是 send 之后,服务器那边响应结果了才会继续执行后面判断 status 的代码,那么不管请求成功还是失败,这个判断一定是可以被正常执行的。但是如果是异步请求呢?对于异步请求,不需要等待服务器响应结果我们就可以执行后面的判断了,甚至可能出现一种情况是:服务器还没来得及响应结果,判断已经先执行了。那么这时候,请求一定会失败。

也就是说,我们需要加一层判断,确保收到服务器的响应结果之后,再去判断请求成功还是失败。这里就用到前面讲过的 xhr.readyState 属性,readyState 会随着 AJAX 的进程而不断变化,我们可以通过 onreadystatechange() 去监听它的变化,进而判断何时收到服务器的响应结果。

readyState 可取值有:

状态值

含义

说明

0

未初始化

尚未调用 open() 方法

1

启动

已经调用 open() 方法,但尚未调用 send() 方法

2

发送

已经调用 send() 方法,但尚未接收到响应

3

接受

已经接收到部分响应数据

4

完成

已经接收到全部响应数据,而且已经可以在客户端使用了

那么,前面的代码就变成了:

代码语言:javascript
复制
xhr.onreadystatechange = function(){
    if (xhr.readystate == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
            alert(xhr.responseText)
        } else {
            alert("Request was unsuccessful: " + xhr.status)
        }
    }
}
3.6 取消异步请求

设想这么一种情况:我们正在上传一张图片(也就是发送一个 AJAX 请求),由于耗时过长,我们决定取消上传,那么取消上传其实就是取消 AJAX 请求,这是通过 abort() 方法实现的。一旦调用这个方法,xhr 就会停止触发事件,而且也不再允许访问任何与响应相关的对象属性。在终止请求之后,不要忘了对 xhr 对象解引用。

正常上传:

取消上传:

4. XMLHttpRequest 2 级

4.1 FormData

通常提交表单数据的时候,这些数据需要经过序列化,虽然 $('#form').serialize() 可以实现序列化,但对于文件流无能为力。而 FormData 不仅可以做到表单序列化,而且支持异步上传二进制文件。

代码语言:javascript
复制
var data = new FormData();
data.append('name','Sam');
// or
var data = new FormData(document.forms[0]);
4.2 超时设定

xhr.timeout 指定一个毫秒为单位的时间,一旦浏览器在这个规定的时间内没有收到响应,就会触发 timeout 事件,执行回调函数。

代码语言:javascript
复制
xhr.onreadystatechange = function () {
  if(xhr.readyState == 4){
    try{
      if((xhr.status >= 200 && xhr.status <300) || xhr.status == 304){
        alert(xhr.responseText);
      }else{
        alert("Request was unsuccessful:" + xhr.status);
      }
    } catch(ex){
      //......
    }
  }
}
xhr.open('get','timeout.php',true);
xhr.timeout = 1000;
xhr.ontimeout = function () {
  alert("Request did not return in a second");
};
xhr.send(null);

注意:这时候很可能出现一种情况,就是超过1秒后浏览器没收到响应,因此终止了请求,而这时候恰好 xhr.status 为4,因此又调用函数进行判断,这个判断需要访问 xhr.status 属性,而请求已经被终止,这个属性是无法访问的,此时要用 try...catch... 捕获这个错误。

4.3 overrideMimeType() 方法

服务器返回的响应头中有一个是 Content-Type,用以告诉客户端返回的资源类型(MIME)以及应该用什么编码去解码。例如 Content-Type:text/html;charset=UTF-8,那么客户端就会通过 UTF-8 对资源进行解码,然后对资源进行 HTML 解析。 但可能存在一种情况:虽然服务器返回数据是 XML,但 MIME 类型指定为 text/plain,那么这时候客户端就会当作纯文本去处理了,这显然不对,所以我们可以利用 overrideMineType() 方法重写响应的 MIME 类型,这样,客户端就可以将其当作 XML 去处理了。

代码语言:javascript
复制
var xhr = new XMLHttpRequest();
xhr.open('get','text.php',true);
xhr.overrideMineType('text/xml');
xhr.send(null);

注意,必须在 send 调用之前重写。

4.4 进度事件

Progress Events规范规范定义了与客户端与服务器通信相关的一系列事件,这些事件监听了通信进程中的各个关键节点,使我们能够以更细的颗粒度掌控数据传输过程中的细节。有以下6个进度事件:

  • loadstart:在接受到响应数据的第一个字节时触发
  • progress:在接受响应期间持续不断地触发
  • error:在请求错误时触发
  • abort:在因为调用 abort() 方法而终止连接时触发
  • load:在接收到完整的响应数据时触发
  • loadend:在通信完成或触发 error、abort、load 事件后触发 每个请求都从触发 loadstart 事件开始,接下来是一或多个 progress 事件,然后触发 error、abort 或 load 中的一个,最后以触发 loadend 事件结束。

有没有发现,前面的 xhr.readyState == 4 以及这里的 load 事件都可以判断是否接受到完整响应? load 事件实际上简化了这个过程,它不需要像前者那样,既绑定一个监听函数又做一次 readyState 的判断,而只需要绑定监听函数即可。

代码语言:javascript
复制
xhr.onreadystatechange = function () {
  if(xhr.readyState == 4){
    //....
  }
}
// 变成
xhr.onload = function () {
    //....
}

参考:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.XMLHttpRequest 对象
  • 3.AJAX 请求
    • 3.1 创建 XML 对象的实例:
      • 3.2 准备请求
        • 3.3 设置请求头
          • 3.4 发送请求
            • 3.5 处理响应
              • 3.6 取消异步请求
              • 4. XMLHttpRequest 2 级
                • 4.1 FormData
                  • 4.2 超时设定
                    • 4.3 overrideMimeType() 方法
                      • 4.4 进度事件
                      相关产品与服务
                      文件存储
                      文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档