React Hooks / Next.js和Multer:401未经授权,将图像上传到MongoDB Atlas时出错

时间:2020-05-17 15:48:10

标签: node.js mongodb next.js multer mongodb-atlas

我已经尝试了多种配置,并且已经将头发拉出了两天。但是,无论何时尝试打/users/uploadmulter时,我都会得到授权错误。

在mongoDB地图集上,我尝试创建一个新集合。

在我的用户文件中移动路由声明(这样我就知道这不是明确的配置问题,因为其他操作有效,例如,创建用户,获取新密码等)

无论如何,这是我的React组件:

import { useState, useEffect } from 'react';

import { Card, Icon, Image, Segment, Form } from 'semantic-ui-react';

import axios from 'axios';

function ImageUploader() {
  var [defaultImage, setDefaultImage] = useState(
    require('../../assets/images/placeholder.jpg')
  );
  var [userAvatar, setUserAvatar] = useState(defaultImage);

  useEffect(() => {
    setUserAvatar(userAvatar);
  }, [userAvatar]);

  function fileUploader(e) {
    console.log('event fileUploader ', e);
    var imageFormObj = new FormData();

    console.log('e.target.files[0] ', e.target.files[0]);

    imageFormObj.append('avatar', 'multer-image-' + Date.now());
    imageFormObj.append('imageData', e.target.files[0]);
    setUserAvatar(URL.createObjectURL(e.target.files[0]));

    console.log('userAvatar ', userAvatar);
    console.log('imageFormObj ', imageFormObj);

    axios
      .post('http://localhost:8016/users/uploadmulter', imageFormObj)
      .then(data => {
        if (data.data.success) {
          alert('Image has been successfully uploaded using multer');
        }
      })
      .catch(err => {
        alert('Error while uploading image using multer');
      });
  }

  return (
    <>
      <Segment>
        <Card fluid>
          <Image src={userAvatar} alt="upload-image" />
          <Segment>
            <Form encType="multipart/form-data">
              <Form.Field>
                <input
                  placeholder="Name of image"
                  className="process__upload-btn"
                  type="file"
                  name="avatar"
                  content="Edit your Avatar!"
                  onChange={e => fileUploader(e)}
                />
                {/* <Button
                  content="Edit your Avatar!"
                  labelPosition="left"
                  icon="file"
                  onClick={e => fileUploader(e)}
                /> */}
              </Form.Field>
            </Form>
          </Segment>
          <Card.Content>
            <Card.Header>Charly</Card.Header>
            <Card.Meta>
              <span className="date">Joined in 2015</span>
            </Card.Meta>
            <Card.Description>Charly</Card.Description>
          </Card.Content>
          <Card.Content extra>
            <a>
              <Icon name="user" />
              22 Friends
            </a>
          </Card.Content>
        </Card>
      </Segment>
    </>
  );
}

export default ImageUploader;

这是我处理数据发送到MongoDB Atlas的路线:

var router = require('express').Router();
var Image = require('../models/UserImagesSchema');
var multer = require('multer');

  var storage = multer.diskStorage({
  destination: function(req, file, cb) {
    cb(null, './uploads/');
  },
  filename: function(req, file, cb) {
    cb(null, Date.now() + file.originalname);
  }
});

var upload = multer({
  storage: storage,
  limits: {
    fileSize: 1024 * 1024 * 5
  }
});

/*
stores image in uploads folder
using mulkter and creates a reference to the file
*/

router.post(upload.single('imageData'), (req, res, next) => {
  console.log(req.body);
  var newImage = new Image({
    avatar: {
      imageName: req.body.avatar,
      imageData: req.file.path
    }
  });

  newImage
    .save()
    .then(result => {
      console.log(result);
      res.status(200).json({
        success: true,
        document: result
      });
    })
    .catch(err => next(err));
});

module.exports = router;

这是我的架构:

var mongoose = require('mongoose');

/* Image Schema for storing images in the mongodb database */

var UserImagesSchema = new mongoose.Schema({
  avatar: {
    _userId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
    imageName: { type: String, default: 'none', required: true },
    imageData: {
      data: Buffer,
      contentType: String
    }
  }
});

module.exports = mongoose.model('UserImages', UserImagesSchema);

这是Express的应用程序/服务器文件:

var express = require('express');

require('dotenv').config();
var path = require('path');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var cors = require('cors');

var nextJS = require('next');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var bodyParser = require('body-parser');
var auth = require('./lib/auth');
var HttpStatus = require('http-status-codes');
var compression = require('compression');
var helmet = require('helmet');

var PORT = process.env.PORT || 8016;

var { isBlockedPage, isInternalUrl } = require('next-server/dist/server/utils');

function NODE_ENVSetter(ENV) {
  var environment,
    environments = {
      production: () => {
        environment = process.env.MONGODB_URI;
        console.log(`We are currently in the production environment: ${environment}`);
        return environment;
      },
      test: () => {
        environment = process.env.TEST_DB_DSN;
        console.log(`We are currently in the test environment: ${environment}`);
        return environment;
      },
      default: () => {
        environment = process.env.DEVELOPMENT_DB_DSN;
        console.log(`We are currently in the development environment: ${environment}`);
        return environment;
      }
    };
  (environments[ENV] || environments['default'])();

  return environment;
}

var db = NODE_ENVSetter('development');
var mongoose = require('mongoose');

function errorHandler(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 : {};

  // Log error
  console.error(err.stack);

  // Render the error page
  res.status(err.status || 500);

  // Default error message by HTTP code
  res.render('error', {
    title: HttpStatus.getStatusText(err.status),
    message: HttpStatus.getStatusText(err.status)
  });
}

function start() {
  const dev = process.env.NODE_ENV !== 'production';
  const app = nextJS({ dev });
  const server = express();
  // const proxy = createProxyMiddleware(options);

  app
    .prepare()
    .then(() => {
      mongoose.connect(db, { useNewUrlParser: true, useUnifiedTopology: true });
      mongoose.Promise = global.Promise;

      mongoose.connection
        .on('connected', () => {
          console.log(`Mongoose connection open on ${db}`);
        })
        .on('error', err => {
          console.log(`Connection error: ${err.message}`);
        });
    })
    .catch(err => {
      console.error(err);
    });

  server.use(
    session({
      secret: 'very secret 12345',
      resave: false,
      saveUninitialized: false,
      store: new MongoStore({ mongooseConnection: mongoose.connection })
    })
  );

  server.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.header(
      'Access-Control-Allow-Headers',
      'Origin, X-Requested-With, Content-Type, Accept'
    );
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Methods', '*'); // enables all the methods to take place
    return next();
  });

  server.set('view engine', 'html');
  server.use(cors());

  server.use(morgan('dev'));
  server.use('/uploads', express.static('uploads'));
  server.use(bodyParser.json({ limit: '50mb' }));
  server.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
  server.use(cookieParser());
  server.use(express.static(path.join(__dirname + 'uploads')));

  server.use(compression());
  server.use(helmet());
  server.use(auth.initialize);
  server.use(auth.session);
  server.use(auth.setUser);
  // console.log('auth.setUser ', auth.setUser);

  server.use('/users', require('./users'));

  // Redirect all requests to main entrypoint pages/index.js
  server.get('/*', async (req, res, next) => {
    try {
      // @NOTE code duplication from here
      // https://github.com/zeit/next.js/blob/cc6fe5fdf92c9c618a739128fbd5192a6d397afa/packages/next-server/server/next-server.ts#L405
      const pathName = req.originalUrl;
      if (isInternalUrl(req.url)) {
        return app.handleRequest(req, res, req.originalUrl);
      }

      if (isBlockedPage(pathName)) {
        return app.render404(req, res, req.originalUrl);
      }

      // Provide react-router static router with a context object
      // https://reacttraining.com/react-router/web/guides/server-rendering
      req.locals = {};
      req.locals.context = {};
      const html = await app.renderToHTML(req, res, '/', {});

      // Handle client redirects
      const context = req.locals.context;
      if (context.url) {
        return res.redirect(context.url);
      }

      // Handle client response statuses
      if (context.status) {
        return res.status(context.status).send();
      }

      // Request was ended by the user
      if (html === null) {
        return;
      }

      app.sendHTML(req, res, html);
    } catch (e) {
      next(e);
    }
  });

  // catch 404 and forward to error handler
  server.use(function(req, res, next) {
    next(createError(404));
  });

  // error handler
  server.use(function(err, req, res, next) {
    // set locals, only providing error in development
    res.locals.errorStatus = err.status;
    res.locals.errorMessage = err.message;
    res.locals.error = req.app.get('env') === 'development' ? err : {};
    console.log('err.status ', err.status);
    res.status(401).send(err.message);
  });

  if (process.env.NODE_ENV === 'production') {
    server.use(express.static('.next/static'));

    server.get('*', (req, res) => {
      res.sendFile(path.resolve(__dirname, '.next/static', 'index.html'));
    });

    server.listen(PORT, err => {
      if (err) throw err;
      console.log(
        `> Ready and listening on PORT:${PORT} in the ${process.env.NODE_ENV} environment`
      );
    });
  } else {
    server.listen(PORT, err => {
      if (err) throw err;
      console.log(`> Ready and listening on http://localhost:${PORT}`);
    });
  }
}

start();

1 个答案:

答案 0 :(得分:1)

如果文件实际上小于16 mb,请尝试使用此Converter将jpeg / png格式的图像更改为保存为mongodb的格式,您可以将其视为gridfs的简单替代方法

请关注此github存储库以获取更多详细信息,请尝试此方法,

https://github.com/saran-surya/Mongo-Image-Converter