I want to send a images folder along with the other data. (name and openingHours);
this is my vuejs code that I use to submit data to the backend
const formData = new FormData();
formData.append("name", this.name);
formData.append("openingHours", this.openingHours);
formData.append("photos", this.selectedFile);
await this.$http.post("spa", formData);
Here my controller code
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
router.post('/', upload.array('photos', 10), async (req, res) => {
console.log(req.file);
console.log(req.body);
});
Here the req.file is undefined and photos also come under the body and also this openingHours is not an array. I pass and array in the front-end.
This is my body parser settings in the app.js
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());
Can anybody tell me what's wrong with my code?
I want to pass openingHours as an JS array.
UPDATED
this is what I get if I console log openingHours in that method.
You need to stringify your array calling JSON.stringify before saving to FormData:
formData.append("openingHours", JSON.stringify(this.openingHours));
And on the backend you need to parse it calling JSON.parse:
const openingHours = JSON.parse(req.body.openingHours)
Related
I want to make an app that takes a name and an image from user and saves it to the server using multer.
The problem is that i want to validate the name before saving the image, using a middleware before the multer upload middleware.
this is the server code:
const express = require('express');
const app = express();
const ejsMate = require('ejs-mate');
const path = require('path');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.engine('ejs', ejsMate);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static(path.join(__dirname, 'public')));
const validateName = ( req, res, next ) => {
const { name } = req.body;
if ( name.length <= 0 ) return res.send(JSON.stringify({ success: -1 }));
next();
};
app.route('/upload')
.get(( req, res ) => { res.render('index'); })
.post(validateName, upload.single('image_file'), function (req, res) {
console.log(req.file, req.body);
res.send(JSON.stringify({ success: 1 }));
});
app.listen(3000, () => {
console.log("Server started");
});
I am sending the name and image using fetch api:
window.onload = () => {
const submitBtn = document.querySelector("#submit");
const nameInput = document.querySelector('[name="name"');
const imageInput = document.querySelector('[name="image"');
function handleRenderImage() {
console.log( "SUCCESS" );
};
submitBtn.addEventListener('click', async () => {
const formData = new FormData();
const name = nameInput.value;
const image = imageInput.files[0];
formData.append('name', name);
formData.append('image_file', image);
await fetch('/upload', {
method: "POST",
body: formData
})
.then( response => response.json() )
.then( data => {
const { success } = data;
if ( success ) handleRenderImage();
})
.catch(e => { console.error(e); });
});
};
I think the app.use(express.urlencoded({ extended: true })); and app.use(express.json()); is the reason because the request send from client side should be json encoded.
How can i read the req.body inside validateName middleware ?
First off, if you're sending a name and a binary image from a browser, then your data won't be urlencoded or JSON. It will likely have a content-type of multipart/form-data.
You won't get any access to any data from the body of the request until some code reads the body from the stream and parses it for you. If this content-type is multipart/form-data, then you have to use middleware that can read and parse that type (which is something multer can do).
So, what you're kind of asking to do is to read part of the body, parse it, let you look at, then if you like it, read the rest of the body. I'm not aware of any multipart/form-data middleware that will do that easily. It's not even clear to me that the name is guaranteed to arrive BEFORE the image in the data so you might have to read through the whole image just to get to the name anyway.
What I suggest you do instead, is parse the whole response, put the image in a temporary location and then, if the rest of the data looks appropriate, you can then put the image in its final location. If not, you can delete it.
Another possibility would be take the name out of the body and make it a query parameter (this would require custom coding on the client-side). You can then see the query parameter before you've read and parsed the body.
Another possibility would be to split the upload into two parts, the first request would give you the name which you could check independently. The second would then provide the image. You would have to keep some server-side state (perhaps express-session) that has the name that is to be associated with the uploaded image. I would generally not recommend this approach as it has lots of edge cases to deal with and avoiding server-side state between requests when possible is a general design goal.
I posted data on angular front end as formData like this.
postButton(name: string): Observable<any> {
const formData = new FormData();
formData.append('name', name);
return this.http.post(environment.apiUrl + '/url, formData);
}
And I receive data on Node.js front end like this.
const bodyParser = require("body-parser");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/url', (req, res, next) => {
console.log(req.body)
res.status(200).json({
'message': 'OK',
});
});
But I get {},empty value.
what is wrong in my code?
Regards.
According to my knowledge, if you are sending some file then using FormData is useful. In other scenario's like this in which you are just sending plain text. You can just send a normal json object and it will work. You can try this.
postButton(name: string): Observable<any> {
return this.http.post(environment.apiUrl + '/url, { name });
}
In case you really want to use FormData then you need to install a npm package as:
npm install multer
And change your app.js to:
var express = require('express');
var app = express();
var multer = require('multer');
var upload = multer();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(upload.array());
app.use(express.static('public'));
app.post('/api/url', function (req, res) {
console.log(req.body);
});
module.exports = app;
Now, what multer does is, it supports multi-part form submission. And FromData uses that. To get the data from request body you need to install and configure multer.
Hope this works for you.
Delete the Content-Type header:
postButton(name: string): Observable<any> {
const formData = new FormData();
formData.append('name', name);
const httpOptions = {
headers: new HttpHeaders().delete('Content-Type')
};
return this.http.post(environment.apiUrl + '/url, formData, httpOptions);
}
When the XHR API send method sends a FormData Object, it automatically sets the content type header with the appropriate boundary. When the Angular http service overrides the default content type, the server will get a content type header without the proper boundary.
I try to send image, some text in form data and I try to console.log(req.body) It's always return {} I've read many topic about this
here is my route/index.js
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
router.use(bodyParser.urlencoded({extended:true}));
router.use(bodyParser.json());
router.route('/').post(AdminController.list);
I tryo to add urlencoded but it still not working .
bodyParser cannot handle multipart/form-data
Try Multer, From official docs:
Multer is a node.js middleware for handling multipart/form-data, which
is primarily used for uploading files. It is written on top of busboy
for maximum efficiency
Multer adds a body object and a file or files object to the request
object. The body object contains the values of the text fields of the
form, the file or files object contains the files uploaded via the
form.
See a working example:
const Multer = require('multer');
const multer = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024 // no larger than 5mb, you can change as needed.
}
});
app.post('/upload', multer.single('file'), (req, res) => {
// req.body will contain the text fields, if there were any
fs.createWriteStream('./uploads/' + req.file.originalname)
var fileWriteStream = fs.createWriteStream(req.file.originalname);
fileWriteStream.on('finish', () => {
console.log('file saved successfully');
res.send({ message: 'file saved successfully' })
})
fileWriteStream.end(req.file.buffer)
})
I've searched and tried other results, but none seem to render any results.
I'm trying to post data to the backend using postman as a test. The response is sending the 'success' message, but req.body returns an empty array every time I try. I'm using a node backend, with express and I'm trying to use routes. I've had success before, but for some reason I can't get it this time and my old code doesn't seem to work for this one. If I just log req, rather than req.body, I can see that the body is empty, the params are empty, but the url includes the params. I can post it, but it's rather long and I don't know if it's useful.
Here's the url I'm trying to hit: localhost:3000/?testParam=test&test=boop
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/blogTest', { useNewUrlParser: true });
mongoose.Promise = global.Promise;
const postsRoute = require('./routes/post');
app.use(postsRoute);
module.exports = app;
post.js
const express = require('express');
const router = express.Router();
const postModel = require('../models/post'); //not using this yet
router.get("/", function(req, res){
console.log("Getting Posts...");
postModel.find({}, function(err, posts){
if(err){
res.send("{'status': 'error', 'response': "+err+"}");
}
else if(posts.length < 1){
res.send("{'status': 'null', 'response': {}}");
}
else{
res.send("{'status': 'success', 'response': "+posts+"}");
}
});
});
router.post("/", function(req, res){
console.log(req.body);
res.send('success');
});
module.exports = router;
I'm expecting the console to log {'testParam': 'test','test':'boop'}
also, I've tried parsing req.body as json and stringifying it, but it causes the server to crash.
I think you are confused about http methods and how they work.
req.body is the POST request body, it is the data passed by the client when he sends a POST request to your api endpoint. If you are not sending any data in your POST request, then req.body will be empty.
In your example, to get the data from a request like localhost:3000/?testParam=test&test=boop you would need to look in req.params instead of req.body.
You need to try accessing the params variable of the request by code, trying to go through a log to find params might not be accurate therefore try
router.post("/", function(req, res){
console.log(req.params);
res.send('success');
});
I am using node js with express framework and rest api
for rest api client i am using postman extension with chrome browser
here i am able to get values from option "x-www-form-urlencoded" but i am not able to get values from "form data" i want to get values from "form data" option and also need to upload image file.
please help me any to achieve this. i want to get values from "form data" option and also image. please help me.
Below i have mentioned code what i have used.
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var http = require('http').Server(app);
var mysql = require('mysql');
var util = require('util');
var trim = require('trim');
var validator = require('validator');
var bodyParser = require('body-parser');
var Ingest = require('ingest');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var type = upload.single('recfile');
passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
async = require('async');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/upload', function(req, res){
console.log(req.file); // "form-data" values not able to get here
console.log(req);// "form-data" values not able to get here
console.log('body : '+JSON.stringify(req.body));// "form-data" values not able to get here
});
i didn't set any content type in postman header
app.post('/upload', function(req, res){
console.log('req.headers \n '+JSON.stringify(req.headers));
console.log('req.body.file :- '+req.body.file);
console.log('\n\n req.body :- '+JSON.stringify(req.body));
});
I got the below result for the above code.
req.headers
{"host":"localhost:3001","connection":"keep-alive","content length":"5808","cache-control":"no-cache","origin":"chrome-extension://mkhojklkhkdaghjjfdnphfphiaiohkef","password":"password","user-agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36","username":"User2","content-type":"multipart/form-data; boundary=----WebKitFormBoundaryV4zAIbjEyKYxLRWe","accept":"*/*","accept-encoding":"gzip, deflate","accept-language":"en-US,en;q=0.8","cookie":"connect.sid=s%3Atz4f1ZgJkaAjuDD1sOkMB9rr.Z8EUIyxEcr0EyFQL96v0ExGRidM3SAVTx8IIr52O0OI"}
req.body.file :- undefined
req.body :- {}
Yes the same problem facing me several times and according my experience you do't set the content-type in postman header because it should be undefined and node server automatically set the content type according to requirement. If you set the content-type then you do't get any image and other data in the node server .
You get the image from the req.body.file
you get the other data from req.body
app.use(multipart()) in middleware
Procedure how to use multipart as middleware
var multipart = require('connect-multiparty');
global.app = module.exports = express();
app.use(multipart());
I got solution with help of the below code
var express = require('express');
var router = express.Router();
var util = require("util");
var fs = require("fs");
var formidable = require('formidable');
var path = require('path');
router.post("/upload", function(req, res, next){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
// `file` is the name of the <input> field of type `file`
console.log(files);
console.log(fields);
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
form.on('error', function(err) {
console.error(err);
});
form.on('progress', function(bytesReceived, bytesExpected) {
var percent_complete = (bytesReceived / bytesExpected) * 100;
console.log(percent_complete.toFixed(2));
});
form.on('end', function(fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Location where we want to copy the uploaded file */
var new_location = 'public/images/';
fs.readFile(temp_path, function(err, data) {
fs.writeFile(new_location + file_name, data, function(err) {
fs.unlink(temp_path, function(err) {
if (err) {
console.error(err);
} else {
console.log("success!");
}
});
});
});
});
});
I think you need to use body-parser for this and also need to update your app.js as
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
I was facing same problem I was not able to get form data fields body parser is not enough to get those values. Hitting google searched a lot of stuff about it but nothing works. Here is the solution how I got form data values.
Note: I am using typescript instead of js
Install multer package: npm i multer
Now in app.ts or app.js import accordingly:
import multer from "multer"
Define the multer function
const upload = multer(); // config
After body parser:
app.use(upload.any());