截取页面中 ajax 请求

场景

有这样一个需求:
在一个使用 ajax 的网页中,浏览器使用 ajax 向服务端发出一个 HTTP 请求,我们希望获取到该请求的所有信息的同时,还能获取到服务器的返回数据。

在开始之前,我们先回顾一下 ajax 请求。

ajax 请求有如下两种形式:

$.ajax(url, settings)   // 两个参数
$.ajax(settings)    // 一个参数

第一种形式有两个参数,url 是一个字符串,表示请求地址,settings 是一个对象,包含了其他各种参数。

第二种形式只有一个参数,settings 中包含了 url 信息。

拦截方法

要拦截网页中的 ajax 请求,我们需要重写 $.ajax 函数。

主要思路为:

  1. 保存旧的函数,通过同名函数覆盖旧的函数,这样在调用 $.ajax 请求时,就会执行我们新封装的 $.ajax 函数。
  2. 在重写了 $.ajax 函数后,还需要执行原函数,保证原有逻辑不被改变
  3. 要获取服务端返回数据,还需要重写 success 回调函数,与 2 做法相同

具体步骤为:

  1. 保存原来的 $.ajax 函数为 oldAjax
  2. 重写 $.ajax 函数覆盖 oldAjax 函数,并执行原 oldAjax 函数
  3. 在新的 $.ajax 函数中,保存 oldSuccess 回调函数
  4. 重写 success 回调函数,并执行 oldSuccess 回调函数

上面这段话听起来可能有点难以理解,

下面来看看代码。

代码

let oldAjax = $.ajax;
$.ajax = function(url, settings) {
    // 参数形式为 $.ajax(url, setting) 时
    if(typeof url === 'string') {
        /** 
         * 在这里可以拦截到 ajax 请求所有数据,即:
         * url、data、success、error...
         */
        // 保存原回调函数 success
        const success = settings[0].success;
        // TODO: 处理相应逻辑
        if(url === '/api/xx') {
            // 重写 success 回调函数
            settings[0].success() {
                // 执行原回调函数
                success.apply(this, arguments);
                // TODO
            }
            // 执行原 ajax 函数
            return oldAjax(url, settings);
        }
    } 
    // 调用参数形式为 $.ajax(settings) 时
    // TODO: 处理相应逻辑
    if(url.url === '/api/xxx') {
        const success = url.success;
        url.success = function() {
            success.apply(this, agguments);
            // TODO
        }

        return oldAjax(url);
    }
}

总结:

我们拦截请求时,要遵守一个原则,那就是“不能破坏原来的逻辑”。所以,当我们重写了某个方法的时候,必须要在新的方法里去执行一次原来的方法。