I am trying to upload a single file, and store it in a folder in my app directory. On the frontend, I am successfully selecting a file and adding it to the state of the Uploader component. When I make the POST request to the Node route with Axios, I am getting undefined in the request body.
Here is the component:
import React, { Component } from 'react';
import axios from 'axios';
export default class SandboxGet extends Component {
constructor(props) {
super(props);
this.state = {
file: null
};
}
fileSelectHandler = event => {
const file = event.target.files[0];
this.setState({ file: file.name });
};
fileUploadHandler = () => {
const data = new FormData();
data.append('file', this.state.file);
console.log(data);
axios
.post('http://localhost:4000/upload/', this.state.file, {
// receive two parameter endpoint url ,form data
})
.then(res => {
// then print response status
console.log(res.statusText);
});
};
render() {
return (
<div className="uploaderContainer">
<div className="uploadInput">
<i className="fas fa-upload" />
<button className="uploadBtn">Select Files</button>
<input type="file" name="file" onChange={this.fileSelectHandler} />
<div className="fileName">{this.state.fileName}</div>
</div>
<button className="uploadFile" onClick={this.fileUploadHandler}>
Upload!
</button>
</div>
);
}
}
Here is the Node server:
const express = require('express');
const app = express();
const multer = require('multer');
const cors = require('cors');
app.use(cors());
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '/storage');
},
filename: (req, file, cb) => {
cb(null, Date.now() + '-' + file.originalname);
}
});
const upload = multer({ storage: storage }).single('file');
app.post('/upload', (req, res) => {
console.log(req.file); // => returns nothing
console.log(req.body; // => returns nothing
upload(req, res, function(err) {
if (err instanceof multer.MulterError) {
return res.status(500).json(err);
} else if (err) {
return res.status(500).json(err);
}
return res.status(200).send(req.file);
});
});
app.listen(4000, function() {
console.log('App running on port 3000');
});
I feel like I am getting close, but I am missing a big piece of the puzzle.
You are sending the this.state.file. You need to send the FormData.
In your case it is .post('http://localhost:4000/upload/', data)
Also, you need to send the multipart/form-data header.
const headers = {
'content-type': 'multipart/form-data'
}
Then,
axios.post('http://localhost:4000/upload/', data, {headers});
Related
I have a React.js task that requires me to make a POST request to the server. Now, I want to send a POST request when a user clicks a submit button. But I keep getting these 2 errors:
App.js:19 POST http://localhost:3001/ net::ERR_CONNECTION_RESET
App.js:19 Uncaught (in promise) TypeError: Failed to fetch at handleSubmit (App.js:19:1)
My React code:
import "./App.css";
function App() {
const [inputs, setInputs] = useState({});
const [backendData, setBackendData] = useState();
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setInputs((state) => ({ ...state, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault();
/*when submit is clicked, we are goint to send a POST request so that data of the inputs is created*/
console.log(inputs);
fetch("http://localhost:3001/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(inputs),
});
};
return (
<div className="App">
<form onSubmit={handleSubmit}>
<input
type="text"
name="projectTitle"
onChange={handleChange}
className="project-title"
value={inputs.projectTitle || " "}
/>
<input
type="text"
name="id"
className="id"
onChange={handleChange}
value={inputs.id || " "}
/>
<input type="submit" value="Submit" />
</form>
</div>
);
}
export default App;
My Express code:
const express = require("express");
const app = express();
const fs = require("fs");
const cors = require("cors");
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
var obj = { projects: [] };
app.post("/", (req, res, next) => {
let identifier = req.query.identify; //id of project
fs.readFile("webProjects.json", (err, data) => {
if (err) throw err;
obj = JSON.parse(data);
obj.projects.push({
id: identifier,
title: req.query.project,
description: req.query.description,
});
let json = JSON.stringify(obj);
fs.writeFile("webProjects.json", json, (err) => {
if (err) throw err;
console.log("updatedd", req.body.inputs);
});
});
});
/*when user sends delete request, delete specific data.*/
app.delete("/", (req, res, next) => {
fs.readFile("webProjects.json", (err, data) => {
console.log(data);
obj = JSON.parse(data);
// assign the filtered array back to the original array
obj.projects = obj.projects.filter((item) => {
let url = req.query.identify;
return item.id !== url;
});
console.log(obj);
let json = JSON.stringify(obj);
fs.writeFile("webProjects.json", json, (err) => {
if (err) throw err;
console.log(obj);
});
});
});
/*when user navigates to another page, we display the data of the resource*/
app.get("/api", (req, res, next) => {
fs.readFile("webProjects.json", (err, data) => {
if (err) throw err;
res.json(JSON.parse(data));
console.log("done");
});
});
/*we want to catch all errors, with the requests made to the server.
used the wildcard(*) to make sure that we catch all requests made to the server.
*/
app.get("*", (req, res, next) => {
let err = new Error("There was an error in accessing the page you wanted");
err.statusCode = 404;
next(err);
});
app.use((err, req, res, next) => {
console.log(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
});
let PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log("server has listened");
});
If the front end is created with create-react-app command, the problem might be the proxy one. In your package.json file, you can add proxy as shown below:
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:3001"
I am trying to create a route through which I can upload photos. However as I made so,e changes it stopped working and I am not sure how to make it work.
const multer = require('multer');
// MULTER STORAGE
const multerStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '/upload');
},
filename: (req, file, cb) => {
const ext = file.mimetype.split('/')[1];
// Saving format: user-UserId-DateStamp.ext
//e.g user-608d55c7e512b74ee00791de-1621992912638.jpeg
cb(null, `user-${req.body.userId}-${Date.now()}.${ext}`);
},
});
//MULTER FILTER
const multerFilter = (req, file, cb) => {
//mimetype always starts with image/ then png or jpeg or..
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('You are only allowed to upload image files.', 400), false);
}
};
const uploadDirectory = multer({
storage: multerStorage,
fileFilter: multerFilter,
});
//exports.uploadPhoto = uploadDirectory.single('photo');
//app.use(express.static('./uploads'));
// INCLUDE ERROR CLASS AND ERROR CONTROLLER
const AppError = require('../utils/appError.js');
const errorController = require('./errorController.js');
const { Mongoose } = require('mongoose');
The main problem Im guessing is in this block
//UPLOAD PHOTO
exports.uploadPhoto = uploadDirectory(async (req, res) => {
console.log(req.body);
console.log(req.file);
try {
const newPhoto = await photoModel.create(req.file);
newPhoto.save().then((result) => {
console.log('Saved');
res.status(201).json({
status: 'success',
// data: JSON.parse(JSON.stringify(newPhoto.file)),
});
});
} catch (err) {
console.log('Error in upload');
errorController.sendError(err, req, res);
}
}).single('photo');
Can anybody let me know how to correctly write the exports.uploadPhoto
Originally the last function looked like this
exports.uploadPhoto = async (req, res) => {
console.log(req.body);
console.log(req.file);
try {
const newPhoto = await photoModel.create(req.file);
newPhoto.save().then((result) => {
console.log('Saved');
res.status(201).json({
status: 'success',
// data: JSON.parse(JSON.stringify(newPhoto.file)),
});
});
} catch (err) {
console.log('Error in upload');
errorController.sendError(err, req, res);
}
};
The multer middleware function, in your case uploadDirectory, is usually used before other middleware functions/controllers where you have your business logic (e.g. uploadPhoto).
app.post('/upload', uploadDirectory.single('photo'), uploadPhoto);
Keep your original uploadPhoto function and with the above code you'll have access to the data and file through reg.body and req.file, respectively.
This Request Parsing in Node.js Guide (it's free) will help you with file uploads in Node.js.
i use multer package with node and react and i send a file to node js backend, but always its undefined..
This is React
<div className="file-field input-field">
<div className="btn">
<span>File</span>
<input
type="file"
name="image"
id="image"
onChange={changedImageUpload}
/>
</div>
<div className="file-path-wrapper">
<input className="file-path validate" />
</div>
</div>
and that is onChange file handling method in there i just get first console.log but second and third is not printed
const changedImageUpload = (e) => {
const file = e.target.files[0];
const formData = new FormData();
formData.append("image", file);
console.log(formData, file);
try {
const config = {
Headers: {
"Content-Type": "multipart/form-data",
},
};
axios
.post("/uploads", formData, config)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
} catch (err) {
console.log(err);
}
};
and its Node codes and multer configure
import express from "express";
import multer from "multer";
const route = express.Router();
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(
null,
new Date().toISOString().replace(/[\/\\:]/g, "_") + file.originalname
);
},
});
const multerFilter = (req, file, cb) => {
if (
file.mimetype === "image/png" ||
file.mimetype === "image/jpg" ||
file.mimetype === "image/jpeg"
) {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({ storage: storage, fileFilter: multerFilter });
route.post("/uploads", upload.single("image"), (req, res) => {
try {
// res.send(`/${req.file.path}`);
console.log(req.file);
} catch (err) {
console.log(err);
}
});
and import in app.js
import uploadRoutes from "./Routes/uploadRoutes.js";
app.use(uploadRoutes);
const __dirname = path.resolve();
app.use("/images", express.static(path.join(__dirname, "/images")));
so at printing formData i always get empty object, and if i print req.file i get an undefined in node js
Your filter function is wrong. You are comparing the mimeType to things like jpg which isn't a real MIME type, so your files are always filtered out.
You need to compare to image/png and image/jpeg instead.
I have a full MERN stack project with Redux and AXIOS. I used FormData to upload the images to my node server which has the multer and it works perfectly fine on my localhost even tho console on my chrome said empty? (FormData {}). When it's deployed, my FormData is empty. So I tested my FormData without the files(just the input value from forms) and it passes to the server and has it on req.body.
I tried to add config my formData and didn't work.
What am i doing wrong???
For Example
config: { headers: { 'Content-Type': 'multipart/form-data' } } etc.....
Here are some of my codes:
REACT Form 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....................");
}
);
}
);
ERRORS/ LOGS on my PM2
0|server | 2019-01-13 21:27 -07:00: Server is ready to take messages
0|server | 2019-01-13 21:28 -07:00: req.body!!!!! [Object: null
prototype] {} 0|server | 2019-01-13 21:28 -07:00: req.files!!!!!
[] 0|server | 2019-01-13 21:28 -07:00: { [Error: ENOENT: no such
file or directory, open '/var/www/LCTW/uploads/file-1547440111023']
0|server | 2019-01-13 21:28 -07:00: errno: -2, 0|server |
2019-01-13 21:28 -07:00: code: 'ENOENT', 0|server | 2019-01-13
21:28 -07:00: syscall: 'open', 0|server | 2019-01-13 21:28 -07:00:
path: '/var/www/LCTW/uploads/file-1547440111023', 0|server |
2019-01-13 21:28 -07:00: storageErrors: [] }
on here my req.body and req.files are empty.
BUT
when I commented out files parts out on my node.js, req.body exist!
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' }
I can see two problems in you code
First from the npm page of body-parser
This does not handle multipart bodies, due to their complex and
typically large nature. For multipart bodies, you may be interested in
the following modules:
busboy and connect-busboy
multiparty and connect-multiparty
formidable
multer
So body-parser wont populate the req.body but since you are already using multer here is an example on how to populate the req.body with the multipart/form-data.
app.post('/', upload.none(), function (req, res, next) {
// req.body contains the text fields
})
but since you need files and the above wont work you can use upload.any()
Second your middleware injection is in wrong order.
Change this
var upload = multer({
storage: storage
}).array("file");
to
var upload = multer({
storage: storage
})
And instead of
router.post(
"/",
passport.authenticate("jwt", { session: false }),
(req, res) => {
upload(req, res, err => {
//code
}
);
}
);
do
router.post(
"/",
passport.authenticate("jwt", { session: false }),
upload.array("file"), //or upload.any()
(req, res) => {
//....code
//now req.body sould work
//file should be at req.files
);
}
);
EDIT 1
Add in app.js or index.js or the start point of you app
global.rootPath = __dirname;
global.rootPath will now have the full path to your app. ex /usr/user/Desktop/myapp
using path,join(global.rootPath, "uploads") will give you /usr/user/Desktop/myapp/uploads.
The good thing using path.join is that it handles diffrent OS path systems like Windows and *nix
Always use path.join to create all the paths.
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, path.join(global.rootPath, "uploads")); //you tell where to upload the files,
},
filename: function(req, file, cb) {
cb(null, file.fieldname + "-" + Date.now());
}
});
config: { headers: { 'Content-Type': 'multipart/form-data' } }
The multipart/form-data content type must specify the boundary parameter, which you can't know in advance.
Do not override the Content-Type that will be set automatically by XHR / fetch.
I have successfully used FormData() in my own React code to upload files, but for some reason that I cannot explain myself, the Files need to be appended last. I am wondering if this has to do with the prior reply mentioning the requirement of a boundary parameter and an inability to know it until the actual upload happens.
Try appending your data first, then the files last. I would also just try a single file as a test case. Again, last.
Append these first:
formdata.append("eventtitle", this.state.eventtitle);
formdata.append("description", this.state.description);
formdata.append("name", user.name);
Then call this:
this.state.files.forEach((file, i) => {
const newFile = { uri: file, type: "image/jpg" };
formdata.append("file", file, file.name);
});
Hope it helps. For the record, I also use multer, but I had the same issue while using multer on the server side. Appending data prior to files was my required fix.
Regards,
DB
when you use multer your image is stored in the file property of your request, so req.file, but you have req.files. Not sure if that is your only problem as I see others have commented on stackOverflow, but I think that is an issue as well. Do a console.log(req.file) and make sure I'm right, but I just used multer in my code as well and mine works.
One thing I would like to add here is that You cannot console.log to the FormData Object.
eg:-
var formData = new FormData();
formData.append('username', 'Rahul');
formData.append('username', 'Yogesh');
console.log(formData) // empty:- FormData {}
But that data will be sent to API. you can view that data in API Headers.
I have an Angular 6 app that uploads one file using POST:
submit-form.component.html
<input type="file" id="file" (change)="onFileChange($event.target.files)">
<button (click)="uploadFile()"> Upload </button>
submit-form.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpResponse, HttpEventType } from '#angular/common/http';
import { FileService } from '../file.service';
#Component({
selector: 'app-submit-form',
templateUrl: './submit-form.component.html',
styleUrls: ['./submit-form.component.css']
})
export class SubmitFormComponent implements OnInit {
constructor( private fileService: FileService) { }
file_to_upload: File;
onFileChange(files: FileList) {
this.file_to_upload = files.item(0);
}
uploadFile() {
this.fileService.uploadFile(this.file_to_upload).subscribe(
(event) => {
if (event.type == HttpEventType.UploadProgress) {
const percentDone = Math.round(100 * event.loaded / event.total);
console.log(`Uploading - %${percentDone}...`);
} else if (event instanceof HttpResponse) {
console.log('File completely loaded!');
}
},
(err) => {
console.log('Upload Error', JSON.stringify(err));
}, () => {
console.log('Done uploading file!');
}
);
}
}
file.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpParams, HttpRequest } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class FileService {
private uploadUrl = 'http://localhost:4200/upload';
constructor(private http: HttpClient) { }
uploadFile(file: File): Observable<any> {
var formData = new FormData();
formData.append('file_to_upload', file, file.name);
var params = new HttpParams();
var httpOptions = {
params: params,
reportProgress: true
};
const req = new HttpRequest('POST', this.uploadUrl, formData, httpOptions);
return this.http.request(req);
}
}
And Node.JS server that saves that file using multer:
server.js
const http = require('http')
const url = require('url')
const path = require('path')
const multer = require('multer')
const express = require('express')
const router = express()
const serverPort = 4200;
router.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
var storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, 'data/upload/'),
filename: (req, file, cb) => {
console.log('Upload file ', file)
cb(null, file.originalname)
}
});
var upload = multer({storage: storage});
router.post('/upload', upload.single('file_to_upload'), (req, res) => {
res.json({'Code': 200, 'Message': 'Success'});
});
router.listen(serverPort, () => console.log(`Server running at http://localhost:${serverPort}/`));
On Mozilla it works perfectly with small files (<500MB), but when I upload something bigger, the browser freezes between Uploading - 100% and File completely loaded!, rapidly raises it's memory consumption by approximately 1.5x file size and then instantly drops back down, outputting File completely loaded! and Done uploading file! (judging by data/upload/ folder, the file finishes uploading somewhere at the beginning of a memory spike). On Chrome file size does not matter - it always works properly (even with >3GB files).
If I use HTML's <form> for file upload, like this:
<form action="http://localhost:4200/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file_to_upload" >
<input type="submit" value="Upload">
</form>
...then in both browsers there are no sudden memory spikes. So, what's going on?