前端请求大比拼:Fetch、Axios、Ajax、XHR

141 阅读6分钟

前端请求大比拼:Fetch、Axios、Ajax、XHR

XHR

XMLHttpRequest 是一个内置的 JavaScript 对象,XMLHttpRequest(XHR)对象用于与服务器交互。

XMLHttpRequest 在 AJAX 编程中被大量使用。尽管名称包含 XML,XMLHttpRequest 也可以用于获取任何类型的数据,而不仅仅是 XML。它甚至支持 HTTP 以外的协议(包括 file:// 和 FTP)。

缺点 语法复杂 功能限制 XSRF(跨站请求伪造)保护 错误处理 仅限于浏览器环境

请求步骤

  1. 创建 XMLHttpRequest 对象:
let xhr = new XMLHttpRequest();
  1. 设置请求参数:
xhr.open("GET", "https://example.com/api/data", true);
  1. 设置请求头(可选):
xhr.setRequestHeader("Content-Type", "application/json");
  1. 监听状态变化:
xhr.onreadystatechange = () => {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            // 请求成功,处理响应
            console.log(xhr.responseText);
        } else {
            // 请求失败
            console.error("请求失败");
        }
    }
};
  1. 发送请求
xhr.send();

readyStatus : 上面示例中的 readyState 是 XMLHttpRequest 对象的一个属性,用于表示请求的状态。该属性有以下五种可能的取值:

0 (未初始化): XMLHttpRequest 对象已创建,但尚未调用 open 方法。

1 (载入中): open 方法已调用,但尚未调用 send 方法。

2 (载入完成): send 方法已调用,并且响应头和响应状态已经可用。

3 (交互中): 正在接收响应数据,此时部分响应内容可能已经可以访问了。

4 (完成): 响应数据接收完成,整个请求过程已经完全结束。

常见的一些 HTTP 状态码包括:

200 OK:表示请求成功并返回所请求的数据。

201 Created:表示请求成功并在服务器上创建了新资源。

204 No Content:表示请求成功,但响应中无返回的内容。

400 Bad Request:表示请求有语法错误或参数错误,服务器无法理解。

401 Unauthorized:表示请求未经授权,需要用户进行身份验证。

403 Forbidden:表示服务器拒绝请求,通常是因为请求的资源没有访问权限。

404 Not Found:表示请求的资源不存在。

500 Internal Server Error:表示服务器内部发生错误,无法完成请求。

Ajax

AJAX(Asynchronous JavaScript and XML,异步 JavaScript 和 XML)是一种使用现有的网页技术来创建异步请求和更新页面内容的方法。

Ajax 是基于浏览器提供的 XMLHttpRequest 对象来实

// 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest();

// 指定请求的方法和 URL
xhr.open("GET", "api_url", true); // 第三个参数 true 表示异步请求

// 设置请求头(如果需要)
xhr.setRequestHeader("Content-Type", "application/json"); // 根据实际需求设置请求头

// 注册一个回调函数来处理响应
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        const response = JSON.parse(xhr.responseText); // 处理响应数据
        // 在这里执行相应的操作
        console.log(response);
    }
};

// 发送请求
xhr.send();

缺点

兼容性问题 代码冗余 缺乏默认配置 功能限制 可读性较差

Fetch

Fetch 是一种用于进行网络请求的现代 JavaScript API。

Fetch API 在浏览器中原生支持,并且以 Promise 为基础,使得异步请求更加直观和易用。使用 Fetch API,可以执行各种类型的请求(如 GET、POST、PUT、DELETE 等),发送请求时可以设置请求头、请求参数,以及处理响应数据。

相比 AJAX 优点:

Promise 支持 更简洁的 API 内置的 JSON 解析 更好的错误处理

fetch()

fetch(url, options)
    .then((response) => {
        // 在这里处理响应
    })
    .catch((error) => {
        // 在这里处理错误
    });

response()

fetch(url)
    .then((response) => {
        // 检查响应状态码
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }
        // 定义一个响应类型与解析方法的映射关系
        const responseTypes = new Map([
            ["json", () => response.json()],
            ["text", () => response.text()],
            ["formData", () => response.formData()],
            ["blob", () => response.blob()],
            ["arrayBuffer", () => response.arrayBuffer()],
        ]);
        // 根据响应类型选择相应的解析方法
        const parser = responseTypes.get(response.type);
        if (parser) {
            return parser();
        } else {
            throw new Error("Unsupported response type");
        }
    })
    .then((data) => {
        // 处理数据
        console.log(data);
    })
    .catch((error) => {
        // 处理错误情况
        console.error("Error:", error);
    });

错误处理

async function fetchData() {
    try {
        const response = await fetch("https://api.example.com/data");
        if (response.ok) {
            const data = await response.json();
            console.log(data); // 处理解析后的数据
        } else {
            throw new Error("请求失败");
        }
    } catch (error) {
        console.log(error); // 处理错误
    }
}

fetchData();

Axios

Axios 是一个基于 Promise 网络请求库,用于在浏览器和 Node.js 中进行 HTTP 请求。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

特点:

浏览器和 Node.js Promise API 请求拦截和响应拦截 取消请求 并发请求 自动转换数据 错误处理机制 简洁的 API

axios
    .get("https://api.example.com/data")
    .then((response) => {
        // 处理成功响应
        console.log(response.data);
    })
    .catch((error) => {
        // 处理错误
        console.error(error);
    });

请求方法

axios.request(config)

axios.get(url[, config])

axios.delete(url[, config])

axios.head(url[, config])

axios.options(url[, config])

axios.post(url[, data[, config]])

axios.put(url[, data[, config]])

axios.patch(url[, data[, config]])

多个请求

const axios = require("axios");

// 创建多个请求
const request1 = axios.get("https://api.example.com/data1");
const request2 = axios.get("https://api.example.com/data2");

// 并发发送多个请求
axios
    .all([request1, request2])
    .then(
        axios.spread((response1, response2) => {
            // 处理各个请求的响应
            console.log(response1.data);
            console.log(response2.data);
        })
    )
    .catch((error) => {
        // 处理错误
        console.error(error);
    });

请求拦截,响应拦截

在 Axios 中,可以使用 transformRequest 方法在请求发送之前对请求数据进行转换和处理,它是一个请求拦截器,是一个可选的函数。

axios({
    url: "https://api.example.com/data",
    method: "post",
    data: {
        id: 12345,
        name: "John Doe",
    },
    transformRequest: (data, headers) => {
        // 对请求数据进行转换和处理
        const modifiedData = { ...data }; // 复制原始数据

        // 修改数据或添加额外字段
        modifiedData.extraField = "Extra Value";

        // 修改请求头信息
        headers["Content-Type"] = "application/json";

        return JSON.stringify(modifiedData); // 返回处理后的数据
    },
})
    .then((response) => {
        // 处理成功响应
        console.log(response.data);
    })
    .catch((error) => {
        // 处理错误
        console.error(error);
    });
axios
    .get("https://api.example.com/data", {
        transformResponse: (data) => {
            // 对响应数据进行转换和处理
            const parsedData = JSON.parse(data); // 解析 JSON 字符串

            // 修改数据或添加额外字段
            parsedData.extraField = "Extra Value";

            return parsedData; // 返回处理后的数据
        },
    })
    .then((response) => {
        // 处理成功响应
        console.log(response.data);
    })
    .catch((error) => {
        // 处理错误
        console.error(error);
    });

拦截请求和响应

Axios 中,可以使用拦截器来拦截请求和响应,并在其被发送或接收之前进行一些额外的处理,可以通过 axios.interceptors 对象来添加拦截器。

// 添加请求拦截器
axios.interceptors.request.use(
    (config) => {
        // 在发送请求之前做一些处理
        console.log("请求拦截器");

        // 修改请求配置
        config.headers["Authorization"] = "Bearer token";

        return config;
    },
    (error) => {
        // 处理请求错误
        console.error("请求出错:", error);
    }
);

// 添加响应拦截器
axios.interceptors.response.use(
    (response) => {
        // 在接收到响应数据之前做一些处理
        console.log("响应拦截器");

        // 修改响应数据
        response.data = { ...response.data, extraField: "Extra Value" };

        return response;
    },
    (error) => {
        // 处理响应错误
        console.error("响应出错:", error);
    }
);

// 发送请求
axios
    .get("https://api.example.com/data")
    .then((response) => {
        // 处理成功响应
        console.log(response.data);
    })
    .catch((error) => {
        // 处理请求或响应错误
        console.error(error);
    });

客户端支持 XSRF 防护

跨站请求伪造(简称 XSRF)是一种攻击 Web 应用的方法,其中攻击者将自己伪装成合法且受信任的用户,以影响应用程序与用户浏览器之间的交互。

const options = {
    method: "post",
    url: "/login",
    xsrfCookieName: "XSRF-TOKEN",
    xsrfHeaderName: "X-XSRF-TOKEN",
};

axios(options)
    .then((response) => {
        // 处理成功响应
        console.log(response.data);
    })
    .catch((error) => {
        // 处理请求错误
        console.error(error);
    });

请求进度 Axios 的另一个有趣的功能是能够监控请求的进度,这在下载或上传大文件时特别有用,可以使用 onUploadProgress 和 onDownloadProgress 两个配置选项来实现。

axios
    .post("/upload", data, {
        onUploadProgress: (progressEvent) => {
            const percentCompleted = Math.round(
                (progressEvent.loaded * 100) / progressEvent.total
            );
            console.log(`上传进度:${percentCompleted}%`);
        },
    })
    .then((response) => {
        console.log(response.data);
    })
    .catch((error) => {
        console.error(error);
    });

axios
    .get("/download", {
        onDownloadProgress: (progressEvent) => {
            const percentCompleted = Math.round(
                (progressEvent.loaded * 100) / progressEvent.total
            );
            console.log(`下载进度:${percentCompleted}%`);
        },
    })
    .then((response) => {
        console.log(response.data);
    })
    .catch((error) => {
        console.error(error);
    });

取消请求

在 Axios 中,可以使用取消令牌(cancel token)来取消请求。取消令牌是一个对象,它表示一个具体的取消操作,并允许在需要时中止请求。

// 创建一个取消令牌源
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

// 发送请求
axios
    .get("/api/data", {
        cancelToken: source.token,
    })
    .then((response) => {
        console.log(response.data);
    })
    .catch((error) => {
        if (axios.isCancel(error)) {
            console.log("请求已被取消:", error.message);
        } else {
            console.error(error);
        }
    });

// 取消请求
source.cancel("取消请求的原因");

总结

相对于 Fetch、XMLHttpRequest 和 Ajax,我还是更喜欢 Axios。它提供了简洁易用的 API,统一的错误处理和拦截器支持,取消请求和超时处理功能,以及基于 Promise 的链式调用和跨浏览器兼容性。这些特性使得使用 Axios 更方便、高效,并提供更好的开发体验。

原文地址