React hooks/next.js 和 Multer:401 未经授权,将图像上传到 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();

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

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

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

最新更新