Axios自定义请求函数返回数据异常:projects字段为空问题排查
问题背景
基于Axios封装的makeApiRequest函数在多数场景下运行正常,但调用某接口时,返回的projects字段为空数组;而直接调用Axios发起相同请求,却能获取到非空的projects数据。
相关代码上下文如下:
自定义API函数代码
import axios, { AxiosRequestConfig } from 'axios'; const baseUrl = import.meta.env.VITE_BASE_URL; export type METHODS = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; export async function makeApiRequest( url: string, method: METHODS, body?: object, token?: string ) { const headers: HeadersInit = { 'Content-Type': 'application/json', Accept: 'application/json', }; if (token) { headers.Authorization = `Bearer ${token}`; } const options: AxiosRequestConfig = { method, headers, baseURL: baseUrl, url, data: body, }; return axios(options) .then((res) => res.data) .catch((error) => { throw error.response; }); }
请求调用示例
if (auth.token) { // 直接使用axios axios .get('http://localhost:8080/api/v1/admin', { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}`, }, }) .then((res) => console.log('axios-res', res)) .catch(console.log); // 使用自定义函数 makeApiRequest('/v1/admin', 'GET', {}, auth.token) .then((res) => { if (res) console.log('custom-res', res); }) .catch((error) => throw error); }
后端控制器代码
import * as express from 'express' import models from '@/v1/models/'; const { Admin, Project, RetrievedMedia: media } = models; const adminDetailsController = async (req: express.Request, res: express.Response, next: express.NextFunction) => { try { const { jwt: { id } } = req.body; const admin = await Admin.findOne({ where: { id }, include: [ { model: Project, as: 'projects' }, { model: media, as: 'avatar' }, { model: media, as: 'resume' }, ], }); if (!admin) { return res.status(404).send({ success: false, message: 'No user found' }); } res.status(200).send({ success: true, message: 'Admin details retrived', data: { admin, projects: admin.projects, }, }); } catch (error) { next(error); } }; export default adminDetailsController
排查步骤及解决方案
1. 验证请求URL是否匹配
对比两种调用方式的最终请求URL:
- 直接Axios调用的完整URL:
http://localhost:8080/api/v1/admin - 自定义函数的完整URL:
baseUrl + '/v1/admin'
检查import.meta.env.VITE_BASE_URL的值是否为http://localhost:8080/api。如果baseUrl仅为http://localhost:8080,则自定义函数的请求URL会变成http://localhost:8080/v1/admin,与目标接口/api/v1/admin不符,导致请求到错误端点,返回空数据。
验证方式:在浏览器开发者工具的Network面板中,查看两种请求的完整URL是否一致。
2. 修复GET请求的body参数问题
自定义函数在GET请求时传递了空对象{}作为body,并赋值给Axios配置的data字段。根据HTTP规范,GET请求不应携带请求体,且部分后端框架(如Express)在接收到带body的GET请求时,会解析并覆盖req.body的原有数据。
后端控制器从req.body.jwt.id获取管理员ID,若JWT认证中间件原本会将用户信息写入req.body.jwt,但自定义函数发送的空body会被express.json()中间件解析为{},覆盖原有req.body数据,导致req.body.jwt不存在,查询到的管理员ID异常,最终返回空的projects。
修复方式:修改自定义函数,仅在非GET请求时设置data字段:
const options: AxiosRequestConfig = { method, headers, baseURL: baseUrl, url, // 仅非GET请求携带data ...(method !== 'GET' && { data: body }), };
或在调用自定义函数时,GET请求不传body参数:
makeApiRequest('/v1/admin', 'GET', undefined, auth.token)
3. 确认请求头完全一致
在Network面板中对比两种请求的请求头,确保Authorization(token格式是否正确,如Bearer后是否有空格)、Content-Type等字段完全一致,避免因请求头差异导致后端处理逻辑不同。
4. 调试后端查询逻辑
临时在后端控制器中添加日志,打印两种请求下的req.body和查询到的admin.id:
console.log('req.body:', req.body); console.log('查询到的管理员ID:', admin?.id);
通过日志确认自定义函数请求时的管理员ID是否与直接Axios请求时一致,进一步定位数据查询问题。
内容的提问来源于stack exchange,提问作者Sylvahh

