使用带有 Express 和 Axios 的 Multer 将图像上传到 mongodb

Uploading an image to mongodb using Multer with Express and Axios

我基本上是在尝试制作一个小应用程序,允许管理员用户输入产品的名称、价格和图像,然后可以在另一个页面上查看。详细信息将发送到 mongo 数据库,该数据库将通过前端的 axios post 执行。我可以毫无问题地发送名称和价格,这可以在前端动态看到,但是,我无法将图像发送到 mongo 数据库,我已经尝试了很长一段时间了。

我正在使用 multer 和 axios 尝试发送文件,因为该应用程序是一个 React 应用程序。我认为问题与应用程序后端内的 "req.file" 有关。下面的代码是我的端点:

api.js

var express     = require('express');
var bodyParser  = require('body-parser');
var cors        = require('cors')
var app         = express();
var mongodb     = require('mongodb');
var path        = require('path');
var fsextra     = require('fs-extra');
var fs          = require('fs')
var util        = require('util')
var multer      = require('multer')
var upload      = multer( {dest:  __dirname + '/uploads'} )
var ejs         = require('ejs')

const MongoClient = require('mongodb').MongoClient;

app.use(express.static(path.resolve(__dirname, '../react', 'build')));
app.get('*',(req,res)=>{
  res.sendFile(path.resolve(__dirname, '../react', 'build', 'index.html'));
});
console.log(__dirname)
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname);
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
var db;

mongodb.MongoClient.connect('mongodb://<mydbdetails>', (err, database) => {
  if (err) {
    console.log(err)
    process.exit(1);
  }
  db = database;
  console.log('Database connection is ready')

});
var server= app.listen(process.env.PORT || 8082, function () {
  var port = server.address().port;
  console.log("App now running on port", port);
});



app.post('/api/submitImage', upload.single('inputForm'), function(req,res){
  var file = req.body.file
    if (file == null) {
    // If Submit was accidentally clicked with no file selected...
      //res.render('admin', { title:'Please select a picture file to submit!'});
      res.send({success: false, message: "dsfdsg"})
      console.log('There is no file present')
      console.log(req.file,'file')
  }
  else{
    // read the img file from tmp in-memory location
   var newImg = fs.readFileSync(req.files.path);
   console.log(newImg,'details of the new image')
   // encode the file as a base64 string.
   var encImg = newImg.toString('base64');
   console.log(encImg,'kdfjndodj')
   // define your new document
   var newItem = {
      description: req.body.description,
      contentType: req.file.mimetype,
      size: req.files.size,
      img: Buffer(encImg, 'base64')
    };
    db.collection('products').insert(newItem, function(err, result){
      if(err) {
        console.log(err)
      }
      var newoid = new ObjectId(result.ops[0]._id);
      fs.remove(req.file.path, function(err) {
        if (err) { console.log(err) };
        res.render('./src/components/adminContainer.js', {title:'Thanks for the Picture!'});
      });
    })
  }
})

下一个代码是我尝试使用 Axios 发送它的方式:

import axios from 'axios';

class ProductsApi {

  static submitProduct(name,prices,callback){

      axios.post('http://localhost:8082/api/submitProduct', {name: name, prices: prices})
        .then( response => {
        callback(response)
    })
  }
  static viewName(callback){
    axios.post('http://localhost:8082/api/retrieveName')
      .then( response => {
        return callback(response)
    })
  }
  static viewPrice(callback){
    axios.post('http://localhost:8082/api/retrievePrice')
      .then( response => {
        return callback(response)
    })
  }
  static viewProducts(callback){
    axios.post('http://localhost:8082/api/retrieveProducts')
      .then( response => {
        return callback(response)
    })
  }
  static submitImages(image,callback){
    axios.post('http://localhost:8082/api/submitImage',{image: image})
      .then( response => {
        return callback(response)
        console.log('response has been made,', image,'has been recieved by axios')
    })
  }
}


export default ProductsApi;

最后一个文件是我尝试使用事件处理程序将文件发送到数据库的方式:

  import React, { Component } from 'react'
  import '../App.css'
  import AppHeader from './appHeader.js'
  import ProductsApi from '../api/axios.js'

  const AdminContainer = () => {
    return(
      <div>
      <AppHeader />
      <FormContainer />
      </div>
    )
  }

  class FormContainer extends Component{
    constructor(props){
      super(props);
      this.state={
        file: '',
        inputName: '',
        inputPrice: '',
        image: ''
      };
      this.handleNameChange = this.handleNameChange.bind(this);
      this.handlePriceChange = this.handlePriceChange.bind(this);
      this.handleSubmit = this.handleSubmit.bind(this);
      this.sendName = this.handleSubmit.bind(this);
    }

    handleNameChange(e){
        console.log(e.target.value)
      this.setState({
        name : e.target.value,
      })
    }
    handlePriceChange(e){
        console.log(e.target.value)
      this.setState({
        prices : e.target.value
      })
    }
    sendName(e){
      this.setState({
        inputName: e.target.value,
        inputName:e.target.value
      })
    }

    handleSubmit(e){
      e.preventDefault();


    console.log('attempting to access axios...')
    ProductsApi.submitProduct(this.state.name, this.state.prices, resp => {
        console.log('response has been made', resp)
        //if error message, add to state and show error message on front end
        this.setState({
          inputName:this.state.name,
          inputPrice:this.state.prices
        },function(){
          console.log(resp,'this is resp')
          console.log('Axios has send ',this.state.name,' to the database')

        });
      })

      console.log(this.state.prices,'This is the new price')
      console.log(this.state.name,'This is the new name')

    ProductsApi.submitImages(this.state.image, response => {
        console.log('axios has been notified to submit an image...')
        this.setState({
          image: this.state.image
        },function(){
          console.log('Image submission axios response details are as follows: ', response)
          console.log(this.state.image, ': has been sent to the db')
        })
    })
  }

    render(){
      return(

        <div>
          <h2>Add a new product to the Shop</h2>
          <div className='formWrapper'>
            <div className='center'>
              <form name='inputForm' encType='multipart/form-data' method='post'>
                <label>
                  Name:
                  <input value = {this.state.name} onChange={this.handleNameChange} type="text" placeholder='Name' /><br />
                  Price:
                  <input value = {this.state.prices} onChange={this.handlePriceChange} type='text' /><br />
                </label>
                <label>
                  Choose an Image:
                  <input className='imgInsert' name ='inputForm' type='file'/>
                </label>
                <div>
                <img className = 'previewImage' value={this.state.image}/>
                </div>
                <button className='btn updateBtn' onClick={(e) => this.handleSubmit(e)}>Submit</button>
              </form>
            </div>
          </div>
        </div>
      )
    }

  }


  export default AdminContainer

我在尝试调试时遇到的常见错误是

TypeError: Cannot read property 'path' of undefined."

和"file"未定义。

当使用 multer 保存图像时,您需要确保图像作为表单数据到达服务器。这是因为 multer 需要 multipart/form-data 编码,而在提交带有 ajax 请求的表单时,您不会得到这种编码,除非您专门做了一些事情来实现它。 您可以使用 FormData object. Here 来执行此操作,这是一个正在使用的示例。希望对您有所帮助。