У меня есть полный проект стека MERN с Redux и AXIOS. Я использовал FormData для загрузки изображений на сервер моего узла, на котором установлен мультитер, и он отлично работает на моем локальном хосте, даже если консоль на моем Chrome сказала пустым? (FormData {}). Когда развернуто , мои FormData пусты. Поэтому я проверил мои FormData без файлов (только входное значение из форм), и он передается на сервер и получает его в req.body.
Я пытался добавить config мои formData и не работал.
Что я делаю не так ???
Например
config: { headers: { 'Content-Type': 'multipart/form-data' } }
и т.д .....
Вот некоторые из моих кодов:
РЕАКТ Форма JS
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import TextAreaFieldGroup from "../common/TextAreaFieldGroup";
import InputGroup from "../common/InputGroup";
import { addEventful, upload } from "../../actions/eventfulActions";
import Dropzone from "react-dropzone";
const imageMaxSize = 10000000
; //bytes
const acceptedFileTypes =
"image/x-png, image/png, image/jpg, image/jpeg, image/gif";
const acceptedFileTypesArray = acceptedFileTypes.split(",").map(item => {
return item.trim();
});
class EventfulForm extends Component {
constructor(props) {
super(props);
this.state = {
eventtitle: "",
description: "",
// comments:'',
files: [],
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
componentWillReceiveProps(newProps) {
if (newProps.errors) {
this.setState({ errors: newProps.errors });
}
}
verifyFile(files){
if(files && files.length > 0){
const currentFile = files[0]
const currentFileType = currentFile.type
const currentFileSize = currentFile.size
if(currentFileSize > imageMaxSize){
alert("TOO MANY FILES")
return false
}
if (!acceptedFileTypesArray.includes(currentFileType)) {
alert("IMAGES ONLY")
return false
}
return true
}
}
onSubmit(e) {
e.preventDefault();
const { user } = this.props.auth;
const formdata = new FormData();
this.state.files.forEach((file, i) => {
const newFile = { uri: file, type: "image/jpg" };
formdata.append("file", file, file.name);
});
// const newEventful = {
// eventtitle: this.state.eventtitle,
// description: this.state.description,
// pictures: this.state.pictures,
// name: user.name
// };
formdata.append("eventtitle", this.state.eventtitle);
formdata.append("description", this.state.description);
formdata.append("name", user.name);
this.props.addEventful(formdata);
this.setState({ eventtitle: "" });
this.setState({ description: "" });
this.setState({ files: [] });
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onDrop = (files, rejectedFiles) => {
if(rejectedFiles && rejectedFiles.length > 0){
console.log(rejectedFiles)
this.verifyFile(rejectedFiles)
}
if (files && files.length > 0) {
const isVerified = this.verifyFile(files)
if(isVerified){
console.log(files[0].name);
const formdata = new FormData();
files.map(file => {
formdata.append("file", file, file.name);
});
// formdata.append("file", files[0], files[0].name);
console.log(formdata);
// this.props.upload(formdata);
this.setState({
files: files
});
}
}
};
render() {
const previewStyle = {
display: "inline",
width: 100,
height: 100
};
const { errors, files } = this.state;
return (
<div className="post-form mb-3">
<div className="card card-info">
<div className="card-header bg-info text-white">Create an Event</div>
<div className="card-body">
<form onSubmit={this.onSubmit}>
<div className="form-group">
<InputGroup
placeholder="Create a event title"
name="eventtitle"
value={this.state.eventtitle}
onChange={this.onChange}
error={errors.eventtitle}
/>
{files.length > 0 && (
<Fragment>
<h3>Files name</h3>
{files.map((picture, i) => (
<p key={i}>{picture.name}</p>
))}
</Fragment>
)}
<Dropzone
onDrop={this.onDrop.bind(this)}
accept={acceptedFileTypes}
maxSize={imageMaxSize}
>
<div>
drop images here, or click to select images to upload.
</div>
</Dropzone>
<TextAreaFieldGroup
placeholder="Description"
name="description"
value={this.state.description}
onChange={this.onChange}
error={errors.description}
/>
</div>
<button type="submit" className="btn btn-dark">
Submit
</button>
</form>
</div>
</div>
</div>
);
}
}
EventfulForm.propTypes = {
addEventful: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors,
eventful: state.files
});
export default connect(
mapStateToProps,
{ addEventful, upload }
)(EventfulForm);
My FormAction.js
import axios from "axios";
import {
ADD_EVENTFUL,
GET_ERRORS,
ADD_LIKE,
REMOVE_LIKE,
GET_EVENTFUL,
GET_EVENTFULS,
DELETE_EVENTFUL,
CLEAR_ERRORS,
EVENTFUL_LOADING,
UPLOAD_FILES
} from "./types";
const config = {
onUploadProgress: progressEvent =>
console.log(
"Upload Progress" +
Math.round((progressEvent.loaded / progressEvent.total) * 100) +
"%"
)
};
// Add eventful
export const addEventful = eventfulData => dispatch => {
dispatch(clearErrors());
// .post("/api/eventfuls", eventfulData, config)
axios({
method: 'post',
url: '/api/eventfuls',
data: eventfulData,
config: { headers: { 'Content-Type': 'multipart/form-data' } }
}).then(res =>
dispatch({
type: ADD_EVENTFUL,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
node.js
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const passport = require("passport");
const bodyParser = require("body-parser");
// Eventful model
const Eventful = require("../../models/Eventful");
const User = require("../../models/User");
// Validation
const validateEventfulInput = require("../../validation/eventful");
const validateCommentInput = require("../../validation/comment");
var multer = require("multer");
var fs = require("fs");
var path = require("path");
var btoa = require("btoa");
router.use(
bodyParser.urlencoded({
extended: false
})
);
router.use(bodyParser.json());
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, __dirname + "../../../uploads"); //you tell where to upload the files,
},
filename: function(req, file, cb) {
cb(null, file.fieldname + "-" + Date.now());
}
});
var upload = multer({
storage: storage
}).array("file");
router.use((request, response, next) => {
response.header("Access-Control-Allow-Origin", "*");
response.header(
"Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS"
);
response.header("Access-Control-Allow-Headers", "Content-Type");
next();
});
// @route POST api/eventfuls
// @desc Create eventful
// @access Private
router.post(
"/",
passport.authenticate("jwt", { session: false }),
(req, res) => {
upload(req, res, err => {
console.log("req.body!!!!!", req.body);
const { errors, isValid } = validateEventfulInput(req.body);
// Check Validation
if (!isValid) {
console.log(errors);
// If any errors, send 400 with errors object
return res.status(400).json(errors);
}
console.log("req.files!!!!!", req.files);
if (err) {
console.log(err);
res.status(404).json({
uploadFailed: "Upload failed"
});
} else {
let newArr = [];
for (let file of req.files) {
let fileReadSync = fs.readFileSync(file.path);
let item = {};
item.image = {};
item.image.data = fileReadSync;
item.image.contentType = "img/png";
newArr.push(item);
fs.unlink(file.path, function(err) {
if (err) {
console.log("error deleting image", file.path);
} else {
console.log("deleted image", file.path);
}
});
}
for (var i = 0; i < newArr.length; i++) {
var base64 = btoa(
new Uint8Array(newArr[i].image.data).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);
newArr[i].image.data = base64;
}
console.log("33333333333333333333", newArr);
const newEventful = new Eventful({
title: req.body.eventtitle,
description: req.body.description,
pictures: newArr,
user: req.user.id,
name: req.user.name
});
newEventful.save().then(eventful => res.json(eventful));
}
console.log("skipped....................");
}
);
}
);
ОШИБКИ / ЛОГИ на моем PM2
0 | сервер | 2019-01-13 21:27 -07: 00: сервер готов принимать сообщения
0 | сервер | 2019-01-13 21:28 -07: 00: req.body !!!!! [Объект: ноль
прототип] {} 0 | сервер | 2019-01-13 21:28 -07: 00: req.files !!!!!
[] 0 | сервер | 2019-01-13 21:28 -07: 00: {[Ошибка: ENOENT: нет такого
файл или каталог, откройте '/ var / www / LCTW / uploads / file-1547440111023']
0 | сервер | 2019-01-13 21:28 -07: 00: errno: -2, 0 | сервер |
2019-01-13 21:28 -07: 00: код: 'ENOENT', 0 | сервер | 2019-01-13
21:28 -07: 00: системный вызов: 'open', 0 | сервер | 2019-01-13 21:28 -07: 00:
путь: '/ var / www / LCTW / uploads / file-1547440111023', 0 | сервер |
2019-01-13 21:28 -07: 00: ошибки хранения: []}
здесь мои req.body и req.files пусты.
НО
когда я закомментировал части файлов в моем node.js, req.body существует!
0|server | 2019-01-13 21:40 -07:00: req.body!!!!! [Object: null prototype] {
0|server | 2019-01-13 21:40 -07:00: eventtitle: 'asdfas',
0|server | 2019-01-13 21:40 -07:00: description: 'asdfads',
0|server | 2019-01-13 21:40 -07:00: name: 'In Soo Yang' }