前端系统课程 - 34. AJAX 是什么鬼

如何发请求

我们知道有一些标签可以发送请求:

  • <form> 表单可以发请求,但是会刷新页面或新开页面。

  • <a> 标签可以发 GET 请求,但是也会刷新页面或新开页面。

  • <img> 标签可以发 GET 请求,但是只能以图片的形式展示。

  • <link> 标签可以发 GET 请求,但是只能以 CSS、favicon 的形式展示。

  • <script> 可以发 GET 请求,但是只能以脚本的形式运行。

但我们想要一种方式可以实现以下功能:

  • 可以发送 GET、POST、PUT、DELETE 等不同类型的请求。

  • 想以什么形式展示就以什么形式展示。

微软的突破

微软在 IE5 率先在 JavaScript 中引入 ActiveX 对象(API),使得 JavaScript 可以直接发起 HTTP 请求。随后,其他浏览器也跟进创造了一个类似的对象,取名为 XMLHttpRequest,并被纳入了 W3C 规范。

什么是 AJAX

Jesse James Garrett 将如下技术取名为 AJAX(Asynchronous JavaScript and XML,异步 JavaScript 和 XML):

  • 使用 XMLHttpRequest 对象发送请求;

  • 服务器返回 XML 格式的字符串;

  • JavaScript 解析 XML,并更新局部页面。

用原生 JavaScript 发送 AJAX 请求

  • 首先通过 new 操作符和 XMLHttpRequest() 构造器创建一个实例对象;

  • 创建好实例对象后,就可以通过此对象的 open() 方法发送 HTTP 请求;这个方法接收五个参数,一般要了解的是前三个:

    • 第一个参数是字符串,代表请求类型,例如 GET 或 POST 等;

    • 第二个参数也是字符串,表示请求的 URL 地址或路径;

    • 第三个不常用但是比较重要,参数类型是布尔值,true 表示异步传输,false 表示同步传输。

  • 然后给这个对象绑定监听 onreadystatechange 事件,这个事件称为“通信状态改变事件”,它监听的其实是 readyState 属性的变化,这个属性用五个数字代表五种状态:

    • 0:UNSENT,代理被创建,但尚未调用 open() 方法。

    • 1:OPENED,open() 方法已经被调用。

    • 2:HEADERS_RECEIVED,send() 方法已经被调用,并且头部和状态已经可获得。

    • 3:LOADING,下载中,responseText 属性已经包含部分数据。

    • 4:DONE,下载操作已完成。

      从前面的列表中可以看出,只要判断 readyState 属性值为 4 时,就说明请求通信成功。

  • 请求成功后,还要判断返回的状态码,也就是 status 的属性值,如果状态码是 200 证明响应成功了。

  • 响应成功后,便可以得到响应返回的数据,这些数据就是 responseText 的属性值,拿到这个值就可以做相应的数据处理。

  • 用 AJAX 发送请求就像打手机,先解锁手机(创建对象),然后输入号码(初始化),再拨通这个号码(发送请求),最后等待接通后通话(等待响应及数据处理)。

  • 一个基础的 AJAX 方法示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function ajax(method, url, async, fnSuccess, fnFail) {
    let ajax;
    // 创建对象
    if (window.XMLHttpRequest) {
    ajax = new XMLHttpRequest();
    } else {
    ajax = new ActiveXObject('Microsoft.XMLHTTP');
    }
    // 初始化
    ajax.open(method, url, async);
    // 发送请求
    ajax.send();
    // 接收请求
    ajax.onreadystatechange = () => {
    if (ajax.readyState === 4) {
    if (ajax.status === 200) {
    console.log('成功!');
    fnSuccess(ajax.responseText);
    } else {
    console.log('失败!');
    fnFail && fnFail();
    }
    }
    };
    }

JSON 与 JavaScript

  • JSON 是“抄袭” JavaScript 部分语法后发明的另一种语言。

  • JSON 中的数据类型和 JavaScript 中的数据类型非常相似,但区别是 JSON 中没有 Undefined 和 Function,并且在 JSON 中,字符串必须使用双引号包裹。

  • JSON 只是一种数据交换格式,它没有原型链,所以无法传输复杂的数据,例如引用数据类型。

  • HTTP 请求返回的数据都是以字符串的形式返回,只不过这些字符串可以符合不同的格式,比如 XML 或 JSON。

  • 服务器返回的 JSON 格式字符串,可以使用浏览器提供的 window.JSON.parse() 方法将其转换为对应的 JavaScript 数据,例如对象,或数组等等。

同源策略

  • 为什么 form 表单提交没有跨域问题,而 AJAX 提交却有跨域问题呢?

    这是因为原页面用 form 表单提交到另一个域名后,会跳转到新页面,原页面的脚本无法获取新页面中的内容,这在浏览器认为是安全的。

    而 AJAX 是可以读取响应内容的,并且不会跳转新页面,所以浏览器不允许 AJAX 被响应;用 AJAX 是可以成功地将请求发送出去的,只是接收不到服务器的响应。

  • 前面的问题其实体现的是浏览器的同源策略;同源策略的含义是:A 网页设置的 Cookie,B 网页不能打开,除非两个网页“同源”,同源指的是“三个相同”,即协议相同域名相同端口相同

  • 如果两个网页非同源,那么三种行为会受到限制:

    • Cookie、LocalStorage 和 IndexDB 无法读取。

    • DOM 无法获得。

    • AJAX 请求发送后无法得到响应。

CORS 跨域

如果要突破同源策略,可以使用 CORS 机制来进行跨域。

CORS(Cross-Origin Resource Sharing,跨源资源共享),是一种允许当前域的资源(比如 HTML、JS 等)被其他域的脚本请求访问的机制。

一般要实现 CORS,需要后端为指定共享的 URL 添加一个响应头,例如:response.setHeader('Access-Control-Allow-Origin', url);如果允许所有的 URL,可以将参数传入一个通配符字符串 '*'