Multer parses multipart form data when using postman, but doesn't parse multipart form data in request from client app

旧城冷巷雨未停 提交于 2021-02-11 13:36:53

问题


I'm trying to use multer to support file upload from my react app client to my node/express backend.

For some background, I've been using postman 6.7.2, node 8.11.1, express 4.16.3, and multer 1.4.1. After following a tutorial, I could use postman to log req.body and see the entries in the formdata; as in I can log the req.body and the req.file in the route handler () and the file even saves. But when I try sending a request from my react app, the req.body logs as {} and the req.file logs as undefined.

This is my app.js file.

if (process.env.NODE_ENV !== 'production') {
  require('dotenv').config();
}

const path = require('path');
const port = process.env.PORT || 4000;
const mongoURI =
  process.env.NODE_ENV !== 'production'
    ? 'mongodb://localhost/mern2'
    : process.env.MONGODB_URI;

// node server dependencies
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');

const app = express();
const routes = require('./controllers/index');
// Server setup for MongoDB
mongoose.connect(mongoURI);
mongoose.set('useCreateIndex', true);
mongoose.Promise = global.Promise;

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

// use router handlers
app.use('/api', routes);


// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  // res.render('error');
});

app.get("*", (req, res) => {
    res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});

app.listen(port, () =>
  console.log('LISTENING FOR REQUESTS ON PORT ' + port)
);

this is my routes file (controllers/index.js)

const express = require('express')
  , router = express.Router();

router.use('/admin', require('./admin'));

module.exports = router;

and this is my route handler, (admin.js)

router.patch('/panel', upload.single('panelImage'), (req, res) => {
  console.log('req.headers', req.headers);
  console.log('req.body', req.body);
  console.log('req.file', req.file);
  res.send({message: 'success'});
});

on the react side, i have a function patchFileReq, which is like a normal patch request accept it adds the multipart form data header and sends a FormData object as the body.

backendUtils.js

export function patchFileReq (url, body, token) {
  var formData = new FormData();
  Object.keys(body).forEach((key) => {
    if(body[key] instanceof File){
      formData.append(key, body[key], body[key].name);
    }
    else {
      formData.append(key, body[key]);
    }
  });
  for (var key of formData.entries()) {
    console.log(key[0] + ' ' + key[1]);
  }
  const headers = prepareFormDataHeaders(prepareAuthorizationHeaders(token));
  return Observable.ajax.patch(url, formData, headers)
    .map(parseAjaxResponse)
    .catch(parseAjaxError);
}

here's the output of admin.js when I use postman:

*** file *** { fieldname: 'testImage',
  originalname: 'bsn_2R_80_test.png',
  encoding: '7bit',
  mimetype: 'image/png' }
req.headers { 'content-type': 'multipart/form-data; boundary=--------------------------069393334143100418462268',
  'cache-control': 'no-cache',
  'postman-token': 'd289023d-956e-4d03-a0b4-073e6ffbd346',
  'user-agent': 'PostmanRuntime/7.6.0',
  accept: '*/*',
  host: 'localhost:4000',
  'accept-encoding': 'gzip, deflate',
  'content-length': '332255',
  connection: 'keep-alive' }
req.body { testfield: 'testvalue' }
req.file { fieldname: 'testImage',
  originalname: 'bsn_2R_80_test.png',
  encoding: '7bit',
  mimetype: 'image/png',
  destination: './uploads',
  filename: 'bsn_2R_80_test.png',
  path: 'uploads/bsn_2R_80_test.png',
  size: 331918 }

And here's the output for admin.js when I use my react app

req.headers { 'x-forwarded-host': 'localhost:3000',
  'x-forwarded-proto': 'http',
  'x-forwarded-port': '3000',
  'x-forwarded-for': '127.0.0.1',
  'accept-language': 'en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7',
  'accept-encoding': 'gzip, deflate, br',
  referer: 'http://localhost:3000/admin-panel/doors-and-sidelites',
  accept: '*/*',
  'content-type': 'multipart/form-data; boundary=--------------------------833495845447745121323852',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
  'x-requested-with': 'XMLHttpRequest',
  origin: 'http://localhost:4000',
  authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVjYzEzMGI5MmM2MjVmM2ZmMWRlNjk3OCIsImVtYWlsIjoiZ3JlZ29yeS50ZXJsZWNraUBnbWFpbC5jb20iLCJpYXQiOjE1NjIyNjc5MTgsImV4cCI6MTU2MjM1NDMxOH0.pb9GfYjiwQRK8TInsbhf1565ENnSBnsoELClLH1SXB0',
  'content-length': '372484',
  connection: 'close',
  host: 'localhost:4000' }
req.body {}
req.file undefined

Just above, where it says

req.body {}
req.file undefined

Is where I'm not seeing what I expect; I would expect to see the same result for req.body and req.file as when I use postman, which can somehow pick up the body and file.

Edit: i'm adding more front end code.

epics/admin.js this is my epic middleware

...

import {adminSavePanelRequest} from '../../lib/backend;

const adminSavePanelSuccess = (payload) => ({payload, type: ADMIN_SAVE_PANEL_SUCCESS});
const adminSavePanelFailure = (payload) => ({payload, type: ADMIN_SAVE_PANEL_FAILURE});
const adminSavePanel = (action$, store) =>
  action$.ofType(ADMIN_SAVE_PANEL)
    .flatMap(() => {
      const state = store.getState();
      var serverPayload = {};
      serverPayload = state.getIn(['adminPanel', 'doorsForm']).toJS();
      return adminSavePanelRequest(serverPayload)
      .map(adminSavePanelSuccess)
      .catch((error) => Rx.Observable.of(error)
        .do((error) => {
        console.log(`Error: ${error}`);
        })
        .map(adminSavePanelFailure)
      )
    });

...

backend.js

import patchFileReq from './backendUtils';

export function adminSavePanelRequest(payload){
  return patchFileReq('/api/admin/panel', payload, getAuthToken());
}

reducers/admin/model.js

export const DoorsForm = new Record({
  _id: '',
  name: '',
  material: '',
  testImage: ''
});

来源:https://stackoverflow.com/questions/56893435/multer-parses-multipart-form-data-when-using-postman-but-doesnt-parse-multipar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!