美文网首页
前端请求接口封装指南

前端请求接口封装指南

作者: 落魂灬 | 来源:发表于2025-07-24 16:18 被阅读0次

在前端开发中,封装请求接口可以提高代码的可维护性、复用性和可读性。下面介绍几种常见的封装方式:

1、基于Fetch API的封装

// http.js
const baseURL = 'https://api.example.com'

async function request(url, options = {}) {
  const headers = {
    'Content-Type': 'application/json',
    ...options.headers
  }
  
  const response = await fetch(`${baseURL}${url}`, {
    ...options,
    headers
  })
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`)
  }
  
  return response.json()
}

export function get(url, options = {}) {
  return request(url, {
    ...options,
    method: 'GET'
  })
}

export function post(url, data, options = {}) {
  return request(url, {
    ...options,
    method: 'POST',
    body: JSON.stringify(data)
  })
}

// 其他方法如 put, delete 等类似

2、基于Axios的封装

// http.js
import axios from 'axios'

const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
})

// 请求拦截器
instance.interceptors.request.use(
  config => {
    // 可以在这里添加token等
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
instance.interceptors.response.use(
  response => {
    // 对响应数据做点什么
    return response.data
  },
  error => {
    // 对响应错误做点什么
    if (error.response) {
      switch (error.response.status) {
        case 401:
          // 处理未授权
          break
        case 404:
          // 处理未找到
          break
        // 其他状态码处理
      }
    }
    return Promise.reject(error)
  }
)

export default instance

3、更高级的封装(结合业务)

// api.js
import http from './http'

export const userAPI = {
  login: (data) => http.post('/user/login', data),
  getUserInfo: (id) => http.get(`/user/${id}`),
  updateUser: (id, data) => http.put(`/user/${id}`, data),
  deleteUser: (id) => http.delete(`/user/${id}`)
}

export const productAPI = {
  getList: (params) => http.get('/products', { params }),
  getDetail: (id) => http.get(`/products/${id}`),
  create: (data) => http.post('/products', data)
  // ...
}

4、使用 TypeScript 增强类型安全

// http.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'

interface IResponse<T> {
  code: number
  message: string
  data: T
}

class HttpClient {
  private instance: AxiosInstance

  constructor(baseURL: string) {
    this.instance = axios.create({ baseURL })
    this.setupInterceptors()
  }

  private setupInterceptors() {
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config) => {
        // 添加token等
        return config
      },
      (error) => Promise.reject(error)
    )
    
    // 响应拦截器
    this.instance.interceptors.response.use(
      (response: AxiosResponse<IResponse<any>>) => {
        if (response.data.code !== 0) {
          return Promise.reject(response.data.message)
        }
        return response.data.data
      },
      (error) => Promise.reject(error)
    )
  }

  public async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return this.instance.get(url, config)
  }

  public async post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
    return this.instance.post(url, data, config)
  }

  // 其他方法...
}

export const http = new HttpClient('https://api.example.com')

使用示例

import { userAPI } from './api'

async function login() {
  try {
    const result = await userAPI.login({
      username: 'admin',
      password: '123456'
    })
    console.log('登录成功', result)
  } catch (error) {
    console.error('登录失败', error)
  }
}

一次发出两个一模一样的请求如何清除一个,通过使用 Axios 的 CancelToken 和请求拦截器,如果已经有相同的请求在进行中,取消之前的请求

//axios封装
import axios from 'axios';
const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
});
// 封装 GET 请求
const get = (url, params, cancelToken) => {
  return instance.get(url, { params, cancelToken });
};
// 封装 POST 请求
const post = (url, data, cancelToken) => {
  return instance.post(url, data, { cancelToken });
};

export default {get,post,};
//使用 CancelToken 取消重复请求
import axios from 'axios';
import api from './api'; // 上面封装的 Axios 实例

const pendingRequests = new Map();
const CancelToken = axios.CancelToken;

const requestInterceptor = (config) => {
  const { url, method, params, data } = config;
  // 生成唯一标识符
  const key = `${method}-${url}-${JSON.stringify(params)}-${JSON.stringify(data)}`;

  if (pendingRequests.has(key)) {
    // 如果已经有相同的请求在进行中,取消之前的请求
    const cancelToken = pendingRequests.get(key);
    cancelToken('Request canceled due to duplicate request');
  }

  // 创建新的取消令牌
  const source = CancelToken.source();
  config.cancelToken = source.token;

  // 将新的请求加入到 pendingRequests 中
  pendingRequests.set(key, source.cancel);

  // 在请求完成后删除该请求
  config.interceptors.response.use(
    (response) => {
      pendingRequests.delete(key);
      return response;
    },
    (error) => {
      pendingRequests.delete(key);
      return Promise.reject(error);
    }
  );

  return config;
};

// 添加请求拦截器
instance.interceptors.request.use(requestInterceptor);

// 示例请求
const fetchUserData = async (userId) => {
  try {
    const response = await api.get(`/users/${userId}`);
    console.log(response.data);
  } catch (error) {
    if (axios.isCancel(error)) {
      console.log('Request was canceled', error.message);
    } else {
      console.error('Error:', error);
    }
  }
};

// 发起两个相同的请求
fetchUserData(1);
fetchUserData(1);

5.封装建议

  1. 统一错误处理:在拦截器中统一处理错误

  2. 请求取消:实现请求取消功能,避免重复请求

  3. 请求重试:对某些特定错误实现自动重试机制

  4. 缓存策略:根据业务需求实现缓存

  5. 加载状态:可以集成全局加载状态管理

  6. Mock数据:开发环境下支持Mock数据

  7. TypeScript支持:提供完整的类型定义

选择哪种封装方式取决于项目规模、团队习惯和技术栈。对于小型项目,简单的Fetch封装可能足够;对于大型项目,基于Axios的完整封装可能更合适。

6. 跨域问题解决(关键配套)

前端发送请求时可能遇到跨域限制(浏览器安全策略),需后端配合或前端配置:

后端:设置Access-Control-Allow-OriginCORS headers
前端:通过Nginx 反向代理(部署时)或开发环境配置代理(如 Vue 的vite.config.js、React 的setupProxy.js)

相关文章

网友评论

      本文标题:前端请求接口封装指南

      本文链接:https://www.haomeiwen.com/subject/sqzinjtx.html