axios + Express + http-proxy 发送post请求后台无法接收body问题修复方法

本文分析了在Vue项目中使用axios调用Express服务器的post和put请求时,因axios默认的数据发送格式与Express的BodyParser冲突,导致后台无法正确解析body数据的问题。通过调整axios的数据发送方式或修改Express的中间件配置,解决了body数据被重复序列化的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

技术背景:vue项目中使用axios调用接口,前端使用Express作为服务器,http-proxy作为api代理服务器。

问题描述:axios发送get请求没有问题,但是当调用post和put请求并携带body体时,请求一直卡在pending状态,后台反馈没有收到body数据,但是我在expess的proxy代理中debugger是能够看到req.body的。

原因分析:baidu+google,加上查看http-proxy的GitHub issues,确定是因为axios默认以application/json形式发送请求数据,而Express服务中,我们又使用了BodyParser,从而导致请求的body数据被json序列化两次,后台接收到的body数据不符合格式。

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

解决办法

一、URLSearchParams API

在浏览器环境,你可以使用 URLSearchParams API,但是并不是所有的浏览器都支持URLSearchParams 。不推荐使用。

const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);

二、querystring/qs

1、axios发送请求时,对body数据进行序列化

const qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));

// Or in another way (ES6),

import qs from 'qs';
const data = { 'bar': 123 };
const options = {
  method: 'POST',
  data: qs.stringify(data),
  url,
};
axios(options);

2、利用axios拦截器,拦截请求并对body数据进行序列化

import qs from "qs";
// ...
_axios.interceptors.request.use(
  function(config) {
    // Do something before request is sent
    config.data = qs.stringify(config.data);
    return config;
  },
  function(error) {
    // Do something with request error
    return Promise.reject(error);
  }
);

三、express服务端处理

假设http-proxy代理了所有以“/api”开头的请求,后台接收application/json形式数据

1、axios已经对参数进行了json序列化,可以不使用bodyparser

var bodyParser = require('body-parser');
// 使用正则表达式过滤/api开头的请求
app.use(/^(?!\/api)/, bodyParser.json());
app.use(/^(?!\/api)/, bodyParser.urlencoded({ extended: true }));

2、http-proxy拦截器,对body参数进行序列化处理

  var proxy = require('http-proxy');
  proxy.on('proxyReq', function(proxyReq, req) {
    //...
    if (req.body && req.complete) {
        var bodyData = JSON.stringify(req.body);
        proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
        proxyReq.write(bodyData);
    }
  });

  //...
  route.use(function(req, res, next) {
      proxy.web(req, res)
  })

 

### 解决方案 当 `axios.post` 请求未被正确解析时,通常是因为前端发送的数据格式与后端期望的格式不匹配。以下是可能的原因及其对应的解决方案: #### 原因分析 1. **数据格式不一致** 如果前端通过 `axios.post` 方法发送 JSON 数据,而后端却期待的是 URL 编码形式 (`application/x-www-form-urlencoded`) 的数据,则会出现无法解析的情况[^3]。 2. **缺少必要的请求头设置** 默认情况下,`axios` 使用 `application/json` 作为 `Content-Type`,但如果后端没有配置相应的中间件来处理 JSON 格式的数据,也会导致参数接收失败[^4]。 3. **序列化工具缺失或错误** 当使用 `qs.stringify()` 或其他类似的库对表单数据进行序列化时,如果方法调用不当或者未正确传递给 `config.data`,也可能引发问题[^1]。 --- #### 实现步骤详解 ##### 方案一:调整后端逻辑以支持JSON格式 确保后端能够正常解析 JSON 类型的数据。例如,在 Express 中可以引入 `body-parser` 来解析 JSON 和 URL 编码两种类型的内容: ```javascript const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); // 支持 json 格式的 body app.use(bodyParser.urlencoded({ extended: true })); // 支持 url-encoded 格式的 body ``` 这样即使客户端发来的数据是以 JSON 形式封装的,服务器也能成功解码并获取其中的关键字参数。 ##### 方案二:更改前端发送方式为form-data 如果不想改动现有服务端架构,也可以改变前端提交的方式,改为 form-data 格式传送信息。利用第三方库如 `qs` 将对象转成查询字符串再赋值给 request payload 即可完成这一操作[^1]: ```javascript import axios from 'axios'; import qs from 'qs'; axios({ method: 'post', url: '/some-endpoint', data: qs.stringify({ key1: value1, key2: value2 }), headers: { 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' } }).then((response)=>{ console.log(response); }); ``` 注意这里设置了自定义 header 明确告知 server 此次通信采用何种编码标准;同时借助于 `qs.stringify` 函数把 js object 转换成适合 http query string 表达的形式[^1]。 ##### 方案三:验证网络环境是否存在干扰因素 除了以上两点外还需排查是否有代理层(Proxy Layer),防火墙(Firewall)或者其他安全设备篡改了原始包结构从而影响到了最终呈现效果。另外确认浏览器缓存机制是否生效也非常重要因为有时候看似新发起的一次ajax call实际上是从cache里读取出来的旧版本响应[^2]. --- ### 示例代码展示 下面给出一段完整的例子演示如何正确地向 spring boot 应用程序发出带有两个字段(a,b)的一个 POST 请求,并打印返回的结果: ```javascript // Frontend Code Example Using Axios For Post Request With Proper Headers Set Up. axios.post( 'http://localhost:8083/test/postParams', { a: 'valueA', b: 'valueB' }, { headers: {'Content-Type': 'application/json'}} ).then(res => { console.log(`Response Data Received:${res.data}`); }) .catch(err=>{ console.error("Error Occurred During The Call:",err.message); }); ``` 与此同时,请记得在 Spring Boot Controller 层面添加 @RequestBody 注解以便自动绑定传入实体类实例成员变量名相同的属性值[^2]: ```java @RestController @RequestMapping("/test") public class TestController { @PostMapping(value="/postParams", consumes="application/json") public ResponseEntity<String> handlePost(@RequestBody Map<String,String> params){ String result=params.getOrDefault("a","defaultA")+","+params.getOrDefault("b","defaultB"); return new ResponseEntity<>(result, HttpStatus.OK); } } ``` --- ### 总结说明 综上所述,解决 `axios.post` 请求未能正确解析的主要途径包括但不限于以下几个方面:一是保证前后两端约定好统一使用的 media type(即 content-type),二是合理运用诸如 `qs`, `json-stringify` 这些辅助函数做好预处理工作,三是仔细检查整个链路上每一个环节有没有潜在隐患阻碍预期行为的发生。只要按照上述指导原则逐一排除故障点,应该就能顺利达成目标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值