Axios 是基于 Ajax 还是 Fetch?从源码解析其实现

在面试中,面试官可能会问到 Axios 是基于 Ajax 还是 Fetch 的问题。很多人可能会直接回答 Ajax 和 Fetch 的区别,但这并不是问题的核心。本文将从源码的角度,深入探讨 Axios 的实现方式,并回答是否可以手动设置其底层请求机制。

1. Axios 的底层实现:基于 Ajax 还是 Fetch?

Axios 是一个广泛使用的 HTTP 请求库,它的底层实现基于 XMLHttpRequest(即 Ajax),而不是 Fetch API。虽然 Fetch API 是现代浏览器提供的原生请求方式,但 Axios 选择使用 XMLHttpRequest 的原因主要有以下几点:

  • 兼容性更好:XMLHttpRequest 支持更广泛的浏览器环境,包括一些老旧的浏览器。
  • 数据格式支持更全面:XMLHttpRequest 支持多种数据格式(如 text、XML、JSON 等),而 Fetch API 默认只支持 JSON。
  • 拦截器机制:Axios 提供了请求和响应拦截器,这些功能在 Fetch API 中需要手动实现。

2. Axios 的核心功能:baseURL 和拦截器

在 Axios 中,baseURL 是一个非常重要的配置项。它允许我们为所有请求设置一个统一的前缀,这在前后端分离的项目中尤为有用。

2.1 baseURL 的优势

  • 统一管理请求地址 :通过 baseURL,我们可以将所有请求的前缀统一管理,避免在每个请求中重复书写相同的域名或路径。
  • 环境切换方便 :可以通过三元运算符等方式,根据当前环境(开发或生产)动态切换 baseURL,简化环境配置。
js 复制代码
const baseURL = process.env.NODE_ENV === 'development' ? '开发地址' : '生产地址';
  • 请求地址拼接 :Axios 会自动将 baseURL 和具体的请求路径拼接,形成完整的请求地址。

2.2 拦截器的实现

Axios 的拦截器机制是其核心功能之一。通过拦截器,我们可以在请求发送前和响应返回后执行一些自定义逻辑。以下是一个简单的拦截器实现示例:

js 复制代码
const axios = simpleAxios({
    baseURL: 'https://api.github.com/'
});

axios.useRequestInterceptor(config => {
    console.log('请求前拦截器', config);
    return config;
});

axios.useResponseInterceptor(response => {
    console.log('响应拦截器', response);
    return response;
});

在这个示例中,useRequestInterceptoruseResponseInterceptor 分别用于添加请求和响应拦截器。拦截器的执行顺序是先请求拦截器,再发送请求,最后执行响应拦截器。

3. 从源码看 Axios 的实现

为了更深入地理解 Axios 的工作原理,我们可以从源码的角度进行分析。以下是一个简化版的 Axios 实现:

js 复制代码
function simpleAxios({ baseURL = '' } = {}) {
    const interceptors = {
        request: [],
        response: []
    };

    const useRequestInterceptor = (interceptor) => {
        interceptors.request.push(interceptor);
    };
    // 响应拦截器
    const useResponseInterceptor = (interceptor) => {
        interceptors.response.push(interceptor);
    };

    const executeInterceptors = (interceptors, config) => {
        return interceptors.reduce((chain, interceptor) => {
            return chain.then(interceptor);
        }, Promise.resolve(config));
    };

    return {
        useRequestInterceptor,
        useResponseInterceptor, // axios 上的拦截器
        // 发送请求
        get(url) {
            return this.sendRequest('GET', `${baseURL}${url}`);
        },
        post(url, data) {
            return this.sendRequest('POST', `${baseURL}${url}`, data);
        },
        sendRequest(method, url, data) { // 封装请求,实际请求位置
            // 1. 执行请求拦截器
            return executeInterceptors(interceptors.request, { method, url, data })
                .then(({ method, url, data }) => new Promise((resolve, reject) => {
                    const xhr = new XMLHttpRequest();
                    xhr.open(method, url, true);

                    // 判data 是否为对象,是则设置请求头,否则不设置
                    if (method === 'POST' && data) {
                        xhr.setRequestHeader('Content-Type', 'application/json');
                    }

                    xhr.onreadystatechange = () => {
                        if (xhr.readyState === 4) {
                            if (xhr.status >= 200 && xhr.status < 300) {
                                try {
                                    const res = JSON.parse(xhr.responseText);
                                    // 2. 执行响应拦截器并等待结果
                                    executeInterceptors(interceptors.response, res)
                                        .then(result => resolve(result))
                                        .catch(reject);
                                } catch (error) {
                                    reject(new Error('响应数据解析失败'));
                                }
                            } else {
                                reject(new Error(`请求失败,状态码: ${xhr.status}`));
                            }
                        }
                    };
                    // 发送请求
                    xhr.send(data ? JSON.stringify(data) : null);
                }));
        }
    };
}

在这个简化版的实现中,我们可以看到 Axios 的核心逻辑:

  • 拦截器的链式调用 :通过 reduce 方法,拦截器被依次执行,形成一个 Promise 链。每个拦截器都可以对请求或响应进行处理,并返回一个新的配置或响应对象。
  • XMLHttpRequest 的使用 :Axios 使用 XMLHttpRequest 对象来发送请求,并通过 onreadystatechange 事件监听请求的状态变化。
  • 请求和响应的封装 :Axios 将请求和响应的逻辑封装在 sendRequest 方法中,确保请求和响应的处理流程清晰且易于扩展。

4. 总结

通过源码分析,我们可以清晰地看到 Axios 是基于 XMLHttpRequest 实现的,而不是 Fetch API。Axios 的设计充分考虑了兼容性、数据格式支持和拦截器机制,使其成为一个功能强大且灵活的 HTTP 请求库。

在实际开发中,Axios 的 baseURL 配置和拦截器机制为我们提供了极大的便利。通过合理地使用这些功能,我们可以更高效地管理请求和响应,提升代码的可维护性和可扩展性。

相关推荐
二哈喇子!3 分钟前
jQuery从入门到应用:选择器、DOM与Ajax综合指南
前端·javascript·ajax
我也爱吃馄饨4 分钟前
Json实现深拷贝的缺点
前端·javascript·json
NoneCoder36 分钟前
工程化与框架系列(35)--前端微服务架构实践
前端·微服务·架构
洛祁枫38 分钟前
前端发布缓存导致白屏解决方案
前端·缓存
二川bro1 小时前
前端高级CSS用法
前端·css
KL's pig/猪头/爱心/猪头1 小时前
使用libwebsocket写一个server
linux·前端
丁总学Java1 小时前
解锁 vue-property-decorator 的秘密:Vue 2 到 Vue 3 的 TypeScript 之旅!✨
前端·vue.js·typescript
MandiGao1 小时前
ECharts 3D地球(铁路线、飞线、标点、图标、文字标注等)
前端·vue.js·3d·echarts
一个处女座的程序猿O(∩_∩)O1 小时前
Vue 过滤器深度解析与应用实践
前端·javascript·vue.js