个人技术总结——Axios 技术详解与实践

222200314吴荣榜 2024-12-09 10:47:55
这个作业属于哪个课程https://bbs.csdn.net/forums/2401_CS_SE_FZU
这个作业要求在哪里https://bbs.csdn.net/topics/619470310
这个作业的目标个人技术总结——Axios 技术详解与实践
其他参考文献

目录

  • Axios 技术详解与实践
  • 1. 技术概述
  • 2. 技术详述
  • 2.1 安装与初始化
  • 安装 Axios
  • 封装 Axios 实例 request.ts
  • 2.2 Axios 的常用请求方法
  • GET 请求
  • POST 请求
  • PUT 请求
  • DELETE 请求
  • 文件上传
  • 并发请求
  • 2.3 API 封装(api.ts)
  • 定义通用返回类型
  • 定义 DTO 类型
  • 封装 API 模块
  • 2.4 在组件中调用 API
  • 示例:创建任务
  • 示例:获取任务列表
  • 3. 技术使用中遇到的问题和解决过程
  • 3.1 跨域请求被阻止
  • 描述
  • 解决方案
  • 3.2 拦截器未正确处理错误
  • 描述
  • 解决方案
  • 3.3 请求重复发送
  • 描述
  • 解决方案
  • 3.4 超时处理
  • 描述
  • 解决方案
  • 3.5 文件上传失败
  • 描述
  • 解决方案
  • 4. 总结
  • 5. 参考文献

Axios 技术详解与实践

1. 技术概述

Axios 是一个基于 Promise 的 HTTP 客户端,可在浏览器和 Node.js 环境中使用。它用于实现 HTTP 请求(如 GET、POST、PUT、DELETE 等),支持全局配置、拦截器、并发请求和请求取消等功能。

在前端开发中,尤其是使用 Vue 3 + TypeScript 时,Axios 是处理异步请求的主流工具之一。相比 fetch 和原生 XMLHttpRequest,Axios 提供了更友好的 API 和更强大的功能。

我们选择学习 Axios,原因如下:

  1. 提高开发效率:简化 HTTP 请求处理流程,便于维护。
  2. 需求灵活:支持全局配置、拦截器等高级功能。
  3. 社区支持:有丰富的文档和生态资源。

Axios 的难点主要在于:

  1. 对复杂场景(如拦截器、并发请求)的灵活配置。
  2. 如何封装和扩展 Axios,使其更贴近实际项目需求。

2. 技术详述

2.1 安装与初始化

安装 Axios

通过 npm 安装 Axios:

npm install axios

封装 Axios 实例 request.ts

首先,封装通用的 Axios 实例 request.ts,提供基础功能,例如全局配置、请求和响应拦截器等。

// src/plugins/request.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";

// 创建 Axios 实例
const service: AxiosInstance = axios.create({
  baseURL: "http://localhost:8080", // 全局基础 URL
  timeout: 15000, // 全局超时时间(毫秒)
});

// 请求拦截器
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    const token = localStorage.getItem("token");
    if (token) {
      config.headers!["Authorization"] = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    if (response.status === 200) {
      return response.data;
    }
    return Promise.reject(new Error("Request failed"));
  },
  (error) => Promise.reject(error)
);

export default service;

2.2 Axios 的常用请求方法

以下是 Axios 提供的常用请求方法,并附有完整示例:

GET 请求

GET 请求用于从服务器获取数据:

const fetchData = async () => {
  const response = await axios.get("/api/data", {
    params: { id: 1 },
  });
  console.log(response);
};

POST 请求

POST 请求用于向服务器提交数据:

const submitData = async () => {
  const payload = { name: "Test", age: 25 };
  const response = await axios.post("/api/data", payload);
  console.log(response);
};

PUT 请求

PUT 请求通常用于更新数据:

const updateData = async (id: string) => {
  const payload = { name: "Updated Name" };
  const response = await axios.put(`/api/data/${id}`, payload);
  console.log(response);
};

DELETE 请求

DELETE 请求用于删除资源:

const deleteData = async (id: string) => {
  const response = await axios.delete(`/api/data/${id}`);
  console.log(response);
};

文件上传

使用 FormData 对象上传文件:

const uploadFile = async (file: File) => {
  const formData = new FormData();
  formData.append("file", file);

  const response = await axios.post("/api/upload", formData, {
    headers: { "Content-Type": "multipart/form-data" },
  });
  console.log(response);
};

并发请求

通过 axios.all 批量发送多个请求:

import axios from "@/plugins/request";

const fetchMultipleData = async () => {
  const [res1, res2] = await axios.all([
    axios.get("/api/data1"),
    axios.get("/api/data2"),
  ]);
  console.log(res1, res2);
};

2.3 API 封装(api.ts

request.ts 基础上封装 API 接口管理模块 api.ts,并通过 TypeScript 的 DTO 和通用返回类型规范数据结构。

定义通用返回类型

// src/types/common.ts
export interface ApiResponse<T = any> {
  code: number;
  data: T;
  message: string;
}

定义 DTO 类型

// src/types/dto.ts
export interface CreateTaskDTO {
  name: string;
  description: string;
  startDate: string;
  endDate: string;
}

export interface FacultyDTO {
  id: string;
  name: string;
}

export interface TaskPageDTO {
  id: string;
  name: string;
  createdAt: string;
}

封装 API 模块

// src/api/api.ts
import service from "@/plugins/request";
import { ApiResponse } from "@/types/common";
import { CreateTaskDTO, FacultyDTO, TaskPageDTO } from "@/types/dto";

const api = {
  createTask(data: CreateTaskDTO) {
    return service.request<ApiResponse<void>>({
      method: "post",
      url: "/api/new-sprout/admin/v1/task/create",
      data,
    });
  },
  getFaculty() {
    return service.request<ApiResponse<FacultyDTO[]>>({
      method: "get",
      url: "/api/new-sprout/admin/v1/faculty",
    });
  },
  getTasks() {
    return service.request<ApiResponse<TaskPageDTO[]>>({
      method: "get",
      url: "/api/new-sprout/admin/v1/task/list",
    });
  },
};

export default api;

2.4 在组件中调用 API

示例:创建任务

<script lang="ts" setup>
import api from "@/api/api";
import { ref } from "vue";

const task = ref({
  name: "",
  description: "",
  startDate: "",
  endDate: "",
});

const createTask = async () => {
  try {
    await api.createTask(task.value);
    console.log("Task created successfully");
  } catch (error) {
    console.error("Failed to create task:", error);
  }
};
</script>

<template>
  <div>
    <input v-model="task.name" placeholder="Task Name" />
    <textarea v-model="task.description" placeholder="Description"></textarea>
    <button @click="createTask">Create Task</button>
  </div>
</template>

示例:获取任务列表

<script lang="ts" setup>
import { ref, onMounted } from "vue";
import api from "@/api/api";
import { TaskPageDTO } from "@/types/dto";

const tasks = ref<TaskPageDTO[]>([]);

const fetchTasks = async () => {
  try {
    const response = await api.getTasks();
    tasks.value = response.data;
  } catch (error) {
    console.error("Failed to fetch tasks:", error);
  }
};

onMounted(fetchTasks);
</script>

<template>
  <ul>
    <li v-for="(task, index) in tasks" :key="index">{{ task.name }}</li>
  </ul>
</template>

3. 技术使用中遇到的问题和解决过程

在使用 Axios 的过程中,我们遇到了一些常见问题。这些问题的解决方案不仅帮助我们优化了代码质量,也为项目的稳定性提供了保障。以下是具体问题的描述与解决过程:

3.1 跨域请求被阻止

描述

跨域问题是前端开发中常见的难点之一。当浏览器的同源策略检测到前端发送的请求目标与当前页面的 URL 不同源时(即协议、域名或端口号之一不一致),会阻止请求的发起或响应的接收。

在开发环境中,我们可以通过开发服务器代理解决跨域问题。但在生产环境中,后端服务需要配置 CORS(跨域资源共享)来支持跨域请求。如果未正确处理,跨域问题仍然会存在。

解决方案

  1. 开发环境中的解决方法
    配置开发服务器的代理功能,使前端与后端的请求路径一致,从而绕过跨域限制:

    // vite.config.ts
    export default {
      server: {
        proxy: {
          "/api": {
            target: "http://localhost:5000", // 后端服务地址
            changeOrigin: true,
          },
        },
      },
    };
    
  2. 生产环境中的解决方法
    后端需要配置 CORS 以允许跨域访问:

    • 在 Node.js (Express) 中:

      const express = require("express");
      const cors = require("cors");
      
      const app = express();
      app.use(
        cors({
          origin: "http://example.com", // 允许的前端地址
          methods: ["GET", "POST", "PUT", "DELETE"],
          credentials: true, // 是否允许发送 Cookie
        })
      );
      
    • 在 Spring Boot 中:

      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.servlet.config.annotation.CorsRegistry;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
      
      @Configuration
      public class WebConfig implements WebMvcConfigurer {
          @Override
          public void addCorsMappings(CorsRegistry registry) {
              registry.addMapping("/**")
                      .allowedOrigins("http://example.com")
                      .allowedMethods("GET", "POST", "PUT", "DELETE")
                      .allowCredentials(true);
          }
      }
      
  3. 验证跨域是否成功
    确保前端在生产环境中可以正常发送跨域请求。如果问题依然存在,可以通过浏览器的开发者工具检查请求头是否包含 Access-Control-Allow-Origin 等正确的 CORS 配置。

3.2 拦截器未正确处理错误

描述

在 Axios 的请求和响应拦截器中,如果未正确返回 Promise.reject,会导致错误无法被组件捕获,进而影响正常的错误处理逻辑。

解决方案

确保在拦截器中使用 Promise.reject 抛出错误,方便调用的组件捕获错误:

// 请求拦截器
axios.interceptors.request.use(
  (config) => config,
  (error) => Promise.reject(error)
);

// 响应拦截器
axios.interceptors.response.use(
  (response) => response,
  (error) => {
    console.error("Error occurred:", error.response?.data || error.message);
    return Promise.reject(error); // 确保错误抛出
  }
);

注意

  1. 在组件中通过 try...catch.catch() 捕获错误。
  2. 使用统一的错误处理方法,例如弹出提示框或记录日志。

3.3 请求重复发送

描述

在用户频繁点击某些按钮时,可能会导致重复发送请求。这不仅增加了服务器的负担,还可能导致意料之外的逻辑错误。

解决方案

通过为每个请求添加唯一标识,拦截重复请求:

const pendingRequests = new Map();

axios.interceptors.request.use((config) => {
  const requestKey = `${config.url}-${config.method}`;
  if (pendingRequests.has(requestKey)) {
    throw new Error("Duplicate request detected");
  }
  pendingRequests.set(requestKey, true);
  return config;
});

axios.interceptors.response.use(
  (response) => {
    const requestKey = `${response.config.url}-${response.config.method}`;
    pendingRequests.delete(requestKey);
    return response;
  },
  (error) => {
    const requestKey = `${error.config.url}-${error.config.method}`;
    pendingRequests.delete(requestKey);
    return Promise.reject(error);
  }
);

3.4 超时处理

描述

在网络环境较差时,请求可能因超时导致用户体验受影响。如果未正确处理超时逻辑,可能会出现长时间等待的情况。

解决方案

设置请求的超时时间,并在超时情况下提供用户反馈:

// 设置全局超时时间
const service = axios.create({
  timeout: 10000, // 超时时间(毫秒)
});

// 捕获超时错误
axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.code === "ECONNABORTED") {
      console.error("Request timeout:", error.message);
    }
    return Promise.reject(error);
  }
);

3.5 文件上传失败

描述

在文件上传时,由于文件过大或服务器处理速度较慢,可能导致请求失败。

解决方案

  1. 分片上传
    将文件切分成小块,分批上传,后端合并文件。

  2. 调整后端设置
    确保后端设置了合理的上传文件大小限制。例如,在 Node.js 中可以通过 express-fileupload 进行设置:

    const fileUpload = require("express-fileupload");
    app.use(
      fileUpload({
        limits: { fileSize: 50 * 1024 * 1024 }, // 文件大小限制为 50MB
      })
    );
    
  3. 前端提供反馈
    在上传时显示进度条,提示用户等待。

const uploadFile = async (file: File) => {
  const formData = new FormData();
  formData.append("file", file);

  try {
    const response = await axios.post("/api/upload", formData, {
      onUploadProgress: (progressEvent) => {
        const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
        console.log(`Upload progress: ${progress}%`);
      },
    });
    console.log("File uploaded successfully:", response);
  } catch (error) {
    console.error("File upload failed:", error);
  }
};

4. 总结

通过对 Axios 的封装与扩展,我们构建了通用的请求管理模块和集中化的 API 管理,这不仅显著提升了代码的复用性与维护性,也为团队协作提供了清晰的接口规范。封装后的模块统一了请求的基础配置、拦截器逻辑和错误处理机制,使得开发流程更加高效和标准化。结合 TypeScript,我们为每个接口定义了 DTO 和返回类型,确保了项目在开发中的类型安全性和数据一致性。这种类型驱动的开发方式,不仅减少了潜在的错误,也通过更好的 IDE 支持提升了开发体验。

在实际使用过程中,我们有效应对了跨域请求、重复请求、超时处理等常见问题,为项目提供了稳定的网络请求支持。同时,通过文件上传优化和错误提示机制可以改善用户的交互体验。Axios 的封装为当前项目带来了显著的价值,同时也为未来的开发积累了重要的经验。通过模块化设计和灵活的扩展能力,Axios 成为了高效开发不可或缺的一部分。

5. 参考文献

...全文
1621 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

113

社区成员

发帖
与我相关
我的任务
社区描述
202401_CS_SE_FZU
软件工程 高校
社区管理员
  • FZU_SE_TeacherL
  • 助教_林日臻
  • 防震水泥
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧