技术背景: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)
  })

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐