如何处理axios请求中post请求的坑

29 阅读2分钟

一、问题描述

  • axios.post() 直接传对象,后端收不到数据。
  • 原因是 axios 默认会把 POST 数据序列化为 JSON 格式,而很多后端(尤其是老项目)默认只识别 application/x-www-form-urlencoded 格式(即表单格式)。
  • 所以数据被 “拦截” 了,本质是前后端数据格式不兼容,而不是 axios 主动拦截

二、代码示例:为什么直接传对象不行?

  1. 错误写法(后端收不到数据)
// 错误示例:直接传对象 
axios.post('/api/login', { 
    username: 'admin',
    password: '123456' }).then(res => { 
    console.log(res)
}).catch(err => { 
    console.error(err) 
})

问题分析

  • axios 默认设置 Content-Type: application/json,发送的是 JSON 字符串:
{ "username": "admin", "password": "123456" }
  • 如果后端是用 PHP、Java 等传统方式读取 $_POSTrequest.getParameter(),它们默认只解析 application/x-www-form-urlencoded 格式,所以读不到 JSON 里的字段,表现为 “数据传不过去”。

三、正确的解决方案(代码实现)

方案一:使用 qs 库,将数据转为表单格式(推荐)

这是最稳妥的方式,和后端传统表单提交格式完全一致。

  1. 安装 qs
npm install qs --save
  1. 封装请求(推荐写法)
import axios from 'axios' 
import qs from 'qs' 

// 创建实例 
const request = axios.create({ 
  baseURL: '/api', 
  timeout: 5000 
}) 

// 请求拦截器:统一处理 POST 数据格式 
request.interceptors.request.use(config => { 
// 只对 POST 请求做处理 
    if (config.method === 'post' && config.data) { 
    // 将 JSON 对象转为 application/x-www-form-urlencoded 格式 
    config.data = qs.stringify(config.data) 
    // 同时修改 Content-Type 头(有些后端需要明确指定)
    config.headers['Content-Type'] = 'application/x-www-form-  urlencoded'
} 
  return config 
}, error => { 
  return Promise.reject(error) 
}) 
// 使用 
request.post('/login', { 
  username: 'admin', 
  password: '123456' 
})

发送的数据格式

username=admin&password=123456

后端可以直接用 $_POST['username']request.getParameter("username") 读取。

方案二:手动设置 FormData(适合上传文件或混合数据)

const formData = new FormData() 
formData.append('username', 'admin') 
formData.append('password', '123456') 

axios.post('/api/login', formData, { 
    headers: { 
        'Content-Type': 'multipart/form-data' 
    }
})

适用场景

  • 需要上传文件(File 对象)
  • 混合文本和文件数据

方案三:让后端支持 JSON 格式(现代项目首选)

如果后端是 Node.js(Express),可以直接用中间件解析 JSON:

// 后端 Express 示例 
const express = require('express') 
const app = express() 

// 解析 JSON 格式的请求体 
app.use(express.json()) 

// 现在就能直接读取 req.body.username 了 
app.post('/api/login', (req, res) => { 
    const { username, password } = req.body 
    res.send({ username, password }) 
})

前端代码就可以保持最简洁的写法:

axios.post('/api/login', { 
    username: 'admin', 
    password: '123456' 
})

四、总结:为什么说 “axios 有拦截功能”?

这句话其实是对 “默认行为” 的误解:

  • axios 并没有主动 “拦截” 你的数据,而是自动做了序列化
    • GET 请求:自动把参数拼到 URL 上。
    • POST 请求:默认把对象转为 JSON,并设置 Content-Type: application/json
  • 当后端不支持这种格式时,数据就 “传不过去”,看起来像是被拦截了。

最佳实践

  • 新项目:前后端统一使用 JSON 格式,后端配置 express.json() 等中间件。
  • 老项目:用 qs 统一转为表单格式,避免逐个接口处理。