前端面试六之axios

一、axios简介

Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。在浏览器端,Axios 的底层实现是基于原生的 XMLHttpRequest(XHR)。它对 XHR 进行了封装,增加了 Promise 支持、自动转换 JSON 数据、请求和响应拦截器等功能。在 Node.js 环境中,Axios 使用 http 模块来发起请求。

1.1XHR、Fetch API 和 Axios 的区别

1. XMLHttpRequest (XHR)
  • 定义:XHR 是一个较旧的 API,用于在浏览器中发起网络请求。

  • 工作原理 :基于事件驱动,通过监听 onreadystatechange 事件来处理请求状态变化。

  • 优点

    • 兼容性好,支持较旧的浏览器。

    • 提供了丰富的 API,可以实现复杂的网络请求操作。

  • 缺点

    • 基于回调,容易导致回调地狱,代码难以维护。

    • 无法中止请求。

    • 需要手动设置请求头和解析响应。

  • 使用场景:适用于需要兼容旧浏览器的场景。

Fetch API
  • 定义:Fetch 是一个现代的、基于 Promise 的网络请求接口,用于替代 XHR。

  • 工作原理 :基于 Promise,使用 Promise 对象来处理异步请求。

  • 优点

    • 语法简洁,使用 Promise 避免了回调地狱。

    • 支持中止请求(通过 AbortController)。

    • 更好的错误处理。

    • 支持流式传输,适用于大文件上传和下载。

  • 缺点

    • 兼容性较差,在一些较老的浏览器中不支持。

    • 响应处理需要手动调用 .json().text() 等方法。

    • 默认不接受跨域请求,需要通过 CORS 配置。

  • 使用场景:适用于现代 Web 开发,不需要考虑较旧浏览器版本的场景。

3. Axios
  • 定义:Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。

  • 工作原理 :本质上是对 XHR 的封装,在浏览器端使用 XHR,在 Node.js 中使用 http 模块。

  • 优点

    • 基于 Promise,支持 async/await

    • 自动转换 JSON 数据。

    • 支持请求和响应拦截器。

    • 能够取消请求。

  • 缺点

    • 需要额外引入库。

    • 在一些极端情况下(如超时控制)可能不如原生 Fetch 灵活。

  • 使用场景:适用于需要更丰富的功能(如拦截器、自动数据转换)的场景。

1.2axios基于 Promise

Axios 的请求返回的是一个 Promise 对象,这使得它能够很方便地进行异步操作的处理。例如,你可以使用 .then() 方法来处理请求成功的情况,使用 .catch() 方法来处理请求失败的情况。比如:

javascript 复制代码
axios.get('/user')
  .then(response => {
    console.log(response.data); // 处理成功响应
  })
  .catch(error => {
    console.error(error); // 处理错误
  });

二、演示get和post

html 复制代码
<template>
  <div>
    <h1>Axios GET 和 POST 示例</h1>
    <button @click="fetchData">获取数据 (GET)</button>
    <button @click="postData">提交数据 (POST)</button>

    <div v-if="data">
      <h2>获取的数据:</h2>
      <pre>{{ data }}</pre>
    </div>

    <div v-if="postDataResponse">
      <h2>POST 请求的响应:</h2>
      <pre>{{ postDataResponse }}</pre>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      data: null, // 用于存储 GET 请求的响应数据
      postDataResponse: null, // 用于存储 POST 请求的响应数据
    };
  },
  methods: {
    // 发起 GET 请求
    fetchData() {
      axios.get('https://jsonplaceholder.typicode.com/posts/1')
        .then(response => {
          this.data = response.data; // 将响应数据存储到 data 中
        })
        .catch(error => {
          console.error('GET 请求失败:', error);
        });
    },
    // 发起 POST 请求
    postData() {
      const postData = {
        title: 'foo',
        body: 'bar',
        userId: 1,
      };

      axios.post('https://jsonplaceholder.typicode.com/posts', postData)
        .then(response => {
          this.postDataResponse = response.data; // 将响应数据存储到 postDataResponse 中
        })
        .catch(error => {
          console.error('POST 请求失败:', error);
        });
    },
  },
};
</script>

<style>
/* 添加一些简单的样式 */
button {
  margin-right: 10px;
}
</style>
(1)GET 请求
  • 使用 axios.get 方法发起 GET 请求。

  • 请求的 URL 是 https://jsonplaceholder.typicode.com/posts/1,这是一个公共的测试 API,返回一个模拟的帖子数据。

  • 请求成功后,将响应数据存储到 data 属性中,并在页面上显示。

(2)POST 请求
  • 使用 axios.post 方法发起 POST 请求。

  • 请求的 URL 是 https://jsonplaceholder.typicode.com/posts,同样是一个公共的测试 API。

  • 请求体是一个包含 titlebodyuserId 的对象。

  • 请求成功后,将响应数据存储到 postDataResponse 属性中,并在页面上显示。

使用 async/await

javascript 复制代码
methods: {
  async fetchData() {
    try {
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
      this.data = response.data;
    } catch (error) {
      console.error('GET 请求失败:', error);
    }
  },
  async postData() {
    const postData = {
      title: 'foo',
      body: 'bar',
      userId: 1,
    };

    try {
      const response = await axios.post('https://jsonplaceholder.typicode.com/posts', postData);
      this.postDataResponse = response.data;
    } catch (error) {
      console.error('POST 请求失败:', error);
    }
  },
},

三、发送带有请求头和查询参数的请求

html 复制代码
<template>
  <div>
    <h1>Axios 请求头和查询参数示例</h1>
    <button @click="fetchWithHeadersAndParams">发送请求</button>

    <div v-if="response">
      <h2>响应数据:</h2>
      <pre>{{ response }}</pre>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      response: null, // 用于存储响应数据
    };
  },
  methods: {
    // 发送带有请求头和查询参数的 GET 请求
    fetchWithHeadersAndParams() {
      // 定义请求头
      const headers = {
        'Authorization': 'Bearer your_token_here',
        'Custom-Header': 'CustomValue',
      };

      // 定义查询参数
      const params = {
        userId: 1,
        limit: 10,
        status: 'active',
      };

      // 发起请求
      axios.get('https://jsonplaceholder.typicode.com/posts', {
        headers: headers, // 添加请求头
        params: params,  // 添加查询参数
      })
      .then(response => {
        this.response = response.data; // 将响应数据存储到 response 中
      })
      .catch(error => {
        console.error('请求失败:', error);
        this.response = { error: error.message }; // 如果失败,存储错误信息
      });
    },
  },
};
</script>

<style>
button {
  margin-right: 10px;
}
</style>
(1)请求头
  • axios.get 方法中,通过 headers 属性传递自定义请求头。

  • 示例中添加了 AuthorizationCustom-Header 两个请求头。

(2)查询参数
  • axios.get 方法中,通过 params 属性传递查询参数。

  • 查询参数会自动被 Axios 转换为 URL 的查询字符串。例如,params 对象 { userId: 1, limit: 10 } 会被转换为 ?userId=1&limit=10

(3)完整的请求 URL

假设请求头和查询参数都设置好后,最终的请求 URL 会类似于:

https://jsonplaceholder.typicode.com/posts?userId=1&limit=10&status=active

使用 async/await

javascript 复制代码
methods: {
  async fetchWithHeadersAndParams() {
    const headers = {
      'Authorization': 'Bearer your_token_here',
      'Custom-Header': 'CustomValue',
    };

    const params = {
      userId: 1,
      limit: 10,
      status: 'active',
    };

    try {
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts', {
        headers: headers,
        params: params,
      });
      this.response = response.data;
    } catch (error) {
      console.error('请求失败:', error);
      this.response = { error: error.message };
    }
  },
},

四、发送不同格式的请求体

在 Vue 项目中使用 Axios 发送请求时,可以通过配置请求体的格式来满足不同的需求。以下是三种常见的请求体格式的示例:application/x-www-form-urlencodedmultipart/form-dataapplication/json

html 复制代码
<template>
  <div>
    <h1>Axios 请求体格式示例</h1>
    <button @click="sendUrlEncoded">发送 URL 编码数据</button>
    <button @click="sendMultipart">发送 Multipart 数据</button>
    <button @click="sendJson">发送 JSON 数据</button>

    <div v-if="response">
      <h2>响应数据:</h2>
      <pre>{{ response }}</pre>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      response: null, // 用于存储响应数据
    };
  },
  methods: {
    // 发送 URL 编码数据
    sendUrlEncoded() {
      const data = new URLSearchParams();
      data.append('username', 'kimi');
      data.append('password', '123456');

      axios.post('https://jsonplaceholder.typicode.com/posts', data)
        .then(response => {
          this.response = response.data;
        })
        .catch(error => {
          console.error('请求失败:', error);
          this.response = { error: error.message };
        });
    },

    // 发送 Multipart 数据
    sendMultipart() {
      const formData = new FormData();
      formData.append('file', new Blob(['Hello World'], { type: 'text/plain' }), 'example.txt');
      formData.append('description', 'This is a test file');

      axios.post('https://jsonplaceholder.typicode.com/posts', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      })
      .then(response => {
        this.response = response.data;
      })
      .catch(error => {
        console.error('请求失败:', error);
        this.response = { error: error.message };
      });
    },

    // 发送 JSON 数据
    sendJson() {
      const data = {
        title: 'foo',
        body: 'bar',
        userId: 1,
      };

      axios.post('https://jsonplaceholder.typicode.com/posts', data)
        .then(response => {
          this.response = response.data;
        })
        .catch(error => {
          console.error('请求失败:', error);
          this.response = { error: error.message };
        });
    },
  },
};
</script>

<style>
button {
  margin-right: 10px;
}
</style>
(1)发送 URL 编码数据
  • 使用 URLSearchParams 构造请求体。

  • Axios 会自动将 URLSearchParams 转换为 application/x-www-form-urlencoded 格式。

  • 示例代码:

    javascript 复制代码
    const data = new URLSearchParams();
    data.append('username', 'kimi');
    data.append('password', '123456');
    
    axios.post('https://jsonplaceholder.typicode.com/posts', data);
    (2)发送 Multipart 数据
  • 使用 FormData 构造请求体。

  • 需要手动设置请求头 Content-Typemultipart/form-data

  • 示例代码:

    javascript 复制代码
    const formData = new FormData();
    formData.append('file', new Blob(['Hello World'], { type: 'text/plain' }), 'example.txt');
    formData.append('description', 'This is a test file');
    
    axios.post('https://jsonplaceholder.typicode.com/posts', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    });
    (3)发送 JSON 数据
  • 直接发送一个 JavaScript 对象。

  • Axios 会自动将对象序列化为 JSON 格式,并设置请求头 Content-Typeapplication/json

  • 示例代码:

    javascript 复制代码
    const data = {
      title: 'foo',
      body: 'bar',
      userId: 1,
    };
    
    axios.post('https://jsonplaceholder.typicode.com/posts', data);

    五、axios默认配置项

以下是一些常用的 Axios 默认配置项:

配置项 描述
baseURL 基础 URL,请求时会自动拼接
headers 请求头,可以设置通用头或特定方法的头
timeout 请求超时时间(单位为毫秒)
withCredentials 是否允许跨域请求携带凭证(如 cookies)
responseType 响应数据类型(如 jsontextarraybuffer 等)
validateStatus 定义哪些状态码被视为成功响应
transformRequest 请求发送前的数据转换函数
transformResponse 响应数据的转换函数

以下是一个完整的示例,展示如何设置全局默认配置和自定义实例默认配置:

javascript 复制代码
// 设置全局默认配置
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = 'Bearer your_token_here';
axios.defaults.timeout = 3000;

// 创建自定义实例
const customInstance = axios.create({
  baseURL: 'https://api.custom.com',
  headers: {
    'Content-Type': 'application/json'
  }
});

// 修改实例的默认配置
customInstance.defaults.timeout = 5000;

// 使用全局配置发起请求
axios.get('/user').then(response => {
  console.log(response.data);
});

// 使用自定义实例发起请求
customInstance.get('/custom-user').then(response => {
  console.log(response.data);
});

1. 全局默认配置

Axios 允许通过 axios.defaults 设置全局默认配置,这些配置将应用于所有通过 axios 发起的请求。以下是一些常见的全局默认配置:

基础 URL (baseURL) :为所有请求设置一个基础 URL,请求的 URL 会自动拼接在 baseURL 后面。

javascript 复制代码
axios.defaults.baseURL = 'https://api.example.com';

请求头 (headers):设置通用的请求头或特定方法的请求头。

javascript 复制代码
axios.defaults.headers.common['Authorization'] = 'Bearer your_token_here';
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

超时时间 (timeout):设置请求的超时时间(单位为毫秒),超过该时间未响应则请求会被中断。

javascript 复制代码
axios.defaults.timeout = 2500; // 2.5 秒

验证状态码 (validateStatus):定义哪些 HTTP 状态码被视为成功响应。

javascript 复制代码
axios.defaults.validateStatus = function (status) {
  return status >= 200 && status < 300; // 默认值
};

2. 自定义实例默认配置

除了全局配置,Axios 还允许创建自定义实例,并为每个实例设置默认配置。这在项目中需要使用多个不同配置的 Axios 实例时非常有用:

javascript 复制代码
const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 3000,
  headers: {
    'Authorization': 'Bearer your_token_here'
  }
});

// 修改实例的默认配置
instance.defaults.headers.common['Custom-Header'] = 'CustomValue';

3. 配置的优先级

Axios 的配置会按优先级合并,优先级从低到高依次为:

  1. 库默认值 :在 lib/defaults.js 中定义的默认值。

  2. 实例的 defaults 属性 :通过 axios.create() 创建的实例的默认配置。

  3. 请求的 config 参数:在每次请求中传递的配置参数。

    javascript 复制代码
    const instance = axios.create({
      timeout: 2500 // 实例默认超时时间
    });
    
    instance.get('/longRequest', {
      timeout: 5000 // 该请求的超时时间覆盖实例默认值
    });

    六、axios响应数据的格式和状态码

在使用 Axios 发起 HTTP 请求时,响应数据的格式和状态码是两个非常重要的部分。Axios 提供了丰富的响应数据结构,同时允许你根据状态码来处理不同的响应情况。

1. Axios 响应格式

当 Axios 发起请求并收到响应时,它会返回一个响应对象,该对象包含以下属性:

  • data :响应体的内容。Axios 会根据 Content-Type 自动解析响应体。如果是 application/json,它会被解析为 JavaScript 对象。

  • status :HTTP 状态码(如 200404500 等)。

  • statusText :HTTP 状态消息(如 OKNot FoundInternal Server Error 等)。

  • headers:响应头,是一个对象,包含服务器返回的所有响应头。

  • config:请求的配置对象,包含了请求时传递的配置信息。

  • request :原生的请求对象(在浏览器中是 XMLHttpRequest,在 Node.js 中是 http.ClientRequest)。

示例:响应格式

以下是一个示例,展示如何处理 Axios 的响应数据:

javascript 复制代码
import axios from 'axios';

axios.get('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    console.log('响应数据:', response.data); // 响应体内容
    console.log('状态码:', response.status); // HTTP 状态码
    console.log('状态消息:', response.statusText); // HTTP 状态消息
    console.log('响应头:', response.headers); // 响应头
    console.log('请求配置:', response.config); // 请求配置
  })
  .catch(error => {
    console.error('请求失败:', error);
  });

2. 状态码处理

HTTP 状态码是服务器对请求的响应状态的描述。常见的状态码包括:

  • 2xx:成功

    • 200 OK:请求成功。

    • 201 Created:请求成功,且服务器创建了新资源。

    • 204 No Content:请求成功,但没有返回内容。

  • 3xx:重定向

    • 301 Moved Permanently:请求的资源已永久移动到新位置。

    • 302 Found:请求的资源临时移动到新位置。

  • 4xx:客户端错误

    • 400 Bad Request:请求格式错误。

    • 401 Unauthorized:未授权,需要认证。

    • 403 Forbidden:禁止访问。

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

  • 5xx:服务器错误

    • 500 Internal Server Error:服务器内部错误。

    • 502 Bad Gateway:网关错误。

    • 503 Service Unavailable:服务不可用。

示例:根据状态码处理响应

以下是一个示例,展示如何根据状态码处理不同的响应情况:

javascript 复制代码
import axios from 'axios';

axios.get('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    console.log('响应数据:', response.data);

    // 根据状态码处理响应
    switch (response.status) {
      case 200:
        console.log('请求成功:', response.data);
        break;
      case 404:
        console.error('资源未找到');
        break;
      case 500:
        console.error('服务器内部错误');
        break;
      default:
        console.log('其他状态码:', response.status);
    }
  })
  .catch(error => {
    console.error('请求失败:', error);

    // 处理错误响应
    if (error.response) {
      console.error('状态码:', error.response.status);
      console.error('状态消息:', error.response.statusText);
    } else if (error.request) {
      console.error('请求已发送,但未收到响应');
    } else {
      console.error('请求配置错误:', error.message);
    }
  });

3. 自定义状态码处理

你可以通过 validateStatus 配置项自定义哪些状态码被视为成功响应。默认情况下,只有 2xx 状态码被视为成功,但你可以修改这个行为:

javascript 复制代码
import axios from 'axios';

axios.get('https://jsonplaceholder.typicode.com/posts/1', {
  validateStatus: function (status) {
    return status >= 200 && status < 400; // 将 2xx 和 3xx 状态码视为成功
  }
})
.then(response => {
  console.log('响应数据:', response.data);
})
.catch(error => {
  console.error('请求失败:', error);
});

七、Axios 的请求拦截器和响应拦截器

Axios 的请求拦截器和响应拦截器是 Axios 提供的强大功能,用于在请求发送之前和响应返回之后对数据进行处理。它们可以用于多种场景,例如统一设置请求头、添加认证信息、处理错误、格式化响应数据等。

1. 请求拦截器

请求拦截器可以在请求发送之前对请求进行处理。你可以通过 axios.interceptors.request.use() 方法添加请求拦截器。

示例:添加请求拦截器

以下是一个示例,展示如何在请求拦截器中统一设置请求头和添加认证信息:

javascript 复制代码
import axios from 'axios';

// 添加请求拦截器
axios.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    config.headers['Authorization'] = 'Bearer your_token_here'; // 添加认证信息
    config.headers['Custom-Header'] = 'CustomValue'; // 添加自定义请求头
    return config;
  },
  error => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 测试请求
axios.get('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    console.log('响应数据:', response.data);
  })
  .catch(error => {
    console.error('请求失败:', error);
  });

2. 响应拦截器

响应拦截器可以在响应返回之后对响应进行处理。你可以通过 axios.interceptors.response.use() 方法添加响应拦截器。

示例:添加响应拦截器

以下是一个示例,展示如何在响应拦截器中统一处理响应数据和错误:

javascript 复制代码
import axios from 'axios';

// 添加响应拦截器
axios.interceptors.response.use(
  response => {
    // 对响应数据做点什么
    console.log('响应状态码:', response.status);
    return response.data; // 只返回响应数据
  },
  error => {
    // 对响应错误做点什么
    if (error.response) {
      // 请求已发出,但服务器响应的状态码不在 2xx 范围内
      console.error('响应状态码:', error.response.status);
      console.error('响应消息:', error.response.statusText);
    } else if (error.request) {
      // 请求已发出,但没有收到响应
      console.error('请求已发出,但未收到响应');
    } else {
      // 在设置请求时发生了一些事情,触发了一个错误
      console.error('请求配置错误:', error.message);
    }
    return Promise.reject(error);
  }
);

// 测试请求
axios.get('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    console.log('响应数据:', response);
  })
  .catch(error => {
    console.error('请求失败:', error);
  });

3. 自定义实例的拦截器

除了全局拦截器,你还可以为自定义的 Axios 实例添加拦截器。这在项目中需要使用多个不同配置的 Axios 实例时非常有用。

示例:为自定义实例添加拦截器
javascript 复制代码
import axios from 'axios';

// 创建自定义实例
const customInstance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 3000,
});

// 为自定义实例添加请求拦截器
customInstance.interceptors.request.use(
  config => {
    config.headers['Authorization'] = 'Bearer your_token_here';
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

// 为自定义实例添加响应拦截器
customInstance.interceptors.response.use(
  response => {
    return response.data; // 只返回响应数据
  },
  error => {
    console.error('请求失败:', error);
    return Promise.reject(error);
  }
);

// 使用自定义实例发起请求
customInstance.get('/posts/1')
  .then(response => {
    console.log('响应数据:', response);
  })
  .catch(error => {
    console.error('请求失败:', error);
  });

4. 移除拦截器

如果需要移除某个拦截器,可以通过返回的 id 来移除它:

javascript 复制代码
import axios from 'axios';

// 添加请求拦截器并获取 id
const requestInterceptorId = axios.interceptors.request.use(
  config => {
    config.headers['Authorization'] = 'Bearer your_token_here';
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

// 移除请求拦截器
axios.interceptors.request.eject(requestInterceptorId);

// 添加响应拦截器并获取 id
const responseInterceptorId = axios.interceptors.response.use(
  response => {
    return response.data;
  },
  error => {
    return Promise.reject(error);
  }
);

// 移除响应拦截器
axios.interceptors.response.eject(responseInterceptorId);

5. 使用场景

(1)请求拦截器
  • 统一设置请求头 :例如,添加认证信息(如 Authorization)、内容类型(如 Content-Type)等。

  • 添加公共参数:例如,为每个请求添加时间戳或用户 ID。

  • 请求取消 :通过 CancelTokenAbortController 实现请求取消功能。

(2)响应拦截器
  • 统一处理响应数据:例如,只返回响应体中的数据部分。

  • 统一处理错误:例如,根据状态码显示不同的错误消息。

  • 处理重定向 :例如,根据状态码(如 401)跳转到登录页面。

相关推荐
Hilaku4 分钟前
为什么我不再追流行,而是重新研究了 jQuery
前端·javascript·jquery
兔子121355 分钟前
浏览器内容缓存数据量大时的优化方案
前端
G等你下课7 分钟前
JavaScript 中 Promise 的深度解析:异步编程的革新之路
前端·javascript
啃火龙果的兔子17 分钟前
安全有效的 C 盘清理方法
前端·css
海天胜景21 分钟前
vue3 数据过滤方法
前端·javascript·vue.js
天生我材必有用_吴用26 分钟前
深入理解JavaScript设计模式之策略模式
前端
海上彼尚28 分钟前
Vue3 PC端 UI组件库我更推荐Naive UI
前端·vue.js·ui
述雾学java28 分钟前
Vue 生命周期详解(重点:mounted)
前端·javascript·vue.js
洛千陨34 分钟前
Vue实现悬浮图片弹出大图预览弹窗,弹窗顶部与图片顶部平齐
前端·vue.js
咚咚咚ddd35 分钟前
微前端第四篇:qiankun老项目渐进式升级方案(jQuery + React)
前端·前端工程化