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

时间:2017-07-25 14:47:22

标签: mongodb reactjs express axios multer

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

我正在使用multer和axios尝试发送文件,因为应用程序是一个反应应用程序。我认为问题在于" 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:无法读取属性&#39;路径&#39;未定义的。&#34;

和&#34;文件&#34;未定义。

1 个答案:

答案 0 :(得分:0)

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