How to parse JSON assigned to a variable in POST request? [duplicate] - javascript

I am using nodejs + Express (v3) like this:
app.use(express.bodyParser());
app.route('/some/route', function(req, res) {
var text = req.body; // I expect text to be a string but it is a JSON
});
I checked the request headers and the content-type is missing. Even if "Content-Type" is "text/plain" it is parsing as a JSON it seems. Is there anyway to tell the middleware to always parse the body as a plain text string instead of json? Earlier versions of req used to have req.rawBody that would get around this issue but now it does not anymore. What is the easiest way to force parse body as plain text/string in Express?

By default bodyParser.text() handles only text/plain. Change the type options to include */json or */*.
app.use('/some/route', bodyParser.text({type: '*/*'}), function(req, res) {
var text = req.body; // I expect text to be a string but it is a JSON
});
//or more generally:
app.use(bodyParser.text({type:"*/*"}));
You can find the docs here

In express 4.x you can use the text parser from bodyParser
https://www.npmjs.org/package/body-parser
just add in app.js
app.use(bodyParser.text());
Also in the desired route
router.all('/',function(req,res){
console.log(req.body);
})

If you remove the use of the bodyParser() middleware, it should be text. You can view the bodyParser docs for more info: http://www.senchalabs.org/connect/middleware-bodyParser.html
Remove this line:
app.use(express.bodyParser());
EDIT:
Looks like you're right. You can create your own rawBody middleware in the meantime. However, you still need to disable the bodyParser(). Note: req.body will still be undefined.
Here is a demo:
app.js
var express = require('express')
, http = require('http')
, path = require('path')
, util = require('util');
var app = express();
function rawBody(req, res, next) {
req.setEncoding('utf8');
req.rawBody = '';
req.on('data', function(chunk) {
req.rawBody += chunk;
});
req.on('end', function(){
next();
});
}
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.use(rawBody);
//app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
});
app.post('/test', function(req, res) {
console.log(req.is('text/*'));
console.log(req.is('json'));
console.log('RB: ' + req.rawBody);
console.log('B: ' + JSON.stringify(req.body));
res.send('got it');
});
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
test.js
var request = require('request');
request({
method: 'POST',
uri: 'http://localhost:3000/test',
body: {'msg': 'secret'},
json: true
}, function (error, response, body) {
console.log('code: '+ response.statusCode);
console.log(body);
})
Hope this helps.

Express understands by content-type how to decode a body.
It must have specific decoders in middlewares, which is embedded into the library from 4.x:
app.use(express.text())
app.use(express.json())

Two important things to achieve this.
You need to add the text middleware in order to process text in the body
You need to set the content type by adding the right header "Content-type: text/plain" in the request
Here is the sample code for both.
const express = require('express');
const app = express();
const bodyParser = require('body-parser')
//This is the needed text parser middleware
app.use(bodyParser.text());
app.post('/api/health/', (req, res) => {
res.send(req.body);
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on ${port} ${new Date(Date.now())}`));
Save this as index.js.
Install dependencies.
npm i -S express
npm i -S body-parser
Run it.
node index.js
Now send a request to it.
curl -s -XPOST -H "Content-type: text/plain" -d 'Any text or json or whatever {"key":value}' 'localhost:3000/api/health'
You should be able to see it sending back whatever you posted.

You can use the plainTextParser (https://www.npmjs.com/package/plaintextparser) middleware..
let plainTextParser = require('plainTextParser');
app.use(plainTextParser());
or
app.post(YOUR_ROUTE, plainTextParser, function(req, res) {
let text = req.text;
//DO SOMETHING....
});

I did it:
router.route('/')
.post(function(req,res){
var chunk = '';
req.on('data', function(data){
chunk += data; // here you get your raw data.
})
req.on('end', function(){
console.log(chunk); //just show in console
})
res.send(null);
})

Make sure the version of express and bodyParser has been upgraded to the appropriate versions.
Express ˜4.x and bodyParser ˜1.18.x. That should do it. With that in place the following should work
app.use(bodyParser.text());

Related

Express body-parser req.body with formdata is empty object

Somehow my req.body is always empty, maybe you have an idea:
here is my server code:
const Express = require('express');
const bodyParser = require('body-parser');
const app = new Express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.post('/save', (req, res) => {
console.log(req.body) // => {}
res.send(req.body);
});
const env = process.env.NODE_ENV || 'production';
app.listen(3000, err => {
if (err) { return console.error(err); }
console.info(`Server running on http://localhost:${port} [${env}]`);
});
When I try to send formdata with javascript the req.body is empty:
const data = new FormData(document.querySelector('form'));
console.log(data); // seems empty already??? FormData{}??
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/save');
xhr.send(data);
Same with postman:
I don’t understand this…
Sending x-www-form-urlencoded with postman or raw (application/json) works in postman. But sending the same headers with Formdata in javascript will still result in an empty object…
To log every field in formData
let myForm = document.getElementById('myForm');
formData = new FormData(myForm);
for (let [key, value] of formData.entries()) {
console.log(key, value);
}
Fiddle - https://jsfiddle.net/thesumit67/j4znhxa5/1/
To handle it via express use multer.
Here is an example -
https://www.npmjs.com/package/multer
Make sure to add enctype="multipart/form-data" on form element. Otherwise Multer will ignore it.
let multer = require('multer');
let upload = multer();
app.post('/save', upload.fields([]), (req, res) => {
console.log( req.body );
console.log( req.files );
res.sendStatus(200);
});
body-parser is deprecated and isn't a part of Express anymore.
Also, body-parser does not provide the functionality to parse form-data post data.
From the body-parser repository description:
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
From what I understand, the problem may be in the HTML form.
<form action="" method="POST">
<input type="text" name="foo[bar]">
<button>Submit</button>
</form>
Then in the server code it may look something like this.
app.post('/save', (req, res) => {
console.log(req.body.foo) // => {}
res.send(req.body.foo);
});
Again, this post is older so you've probably already fixed it.
I had this same problem, I was using the fetch api, sending form data to an node.js/express backend. The problem was that I had set enctype='multipart/form-data' on the form and I was also setting Content-type: multipart/form-data in the fetch Headers.
Removing the Content-type from the Headers got everything to work.
I got the solution from here => https://github.com/expressjs/multer/issues/411
Express and body parser Version :
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1"
}
app.js:
const express = require('express');
var bodyParser = require('body-parser')
const app = express();
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.use( bodyParser.json());
const baseUrl = '/api/v1/tours';
app.post(baseUrl, (req, res)=>{
console.log(req.body);
res.send('Done');
})
//starting server
const port = 3000;
app.listen(port, ()=>{
console.log(`app running on port ${port}...`);
});
To send raw data please select JSON from the list

req.body isn't appearing as one of key-value pairs, but req.headers and others do

Sample 'Advanced REST Client' Request
I'm using Postman and Advanced REST client to create a basic POST request for the following code -
'use strict';
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var http = require('http');
// configure the app to use bodyParser()
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
//app.listen(6666);
http.createServer(function (req, res) {
h2s(req, res);
}).listen(6666, '127.0.0.1');
console.log('Server running at http://127.0.0.1:6666/');
module.exports = function h2s(req, res) {
console.log("inside h2s");
app.use(function (req, res) {
console.log("req.body : " + req.body);
res.send("OK");
});
}
But, when I debug, I find that req.body is missing in the "req object tree". What's more strange is all the changes that I make to req.headers are available in the req object tree.
Looks like I seem to be making a trivial mistake, but I'm unable to figure it out. Been trouble-shooting for an hour or so but no luck!
Can anyone of you figure out why req.body seems to be missing from the req object tree?
Will be of great help to me. Thanks!
It looks like you have several issues in your code:
instead of
http.createServer(function (req, res) {
h2s(req, res);
}).listen(6666, '127.0.0.1');
console.log('Server running at http://127.0.0.1:6666/');
module.exports = function h2s(req, res) {
console.log("inside h2s");
app.use(function (req, res) {
console.log("req.body : " + req.body);
res.send("OK");
});
}
For creating the server, try
http.createServer(app).listen(8000, '127.0.0.1'); //using http
Or (using express directly)
app.listen(8000,function(){
console.log('Server running at http://127.0.0.1:8000/');
});
Then register an handler function for your requests, there you can access req.body
app.use(function (req, res) {
console.log("req.body : " + req.body);
res.send("OK");
});
Dear u set body parser Url Encoding to true
// configure the app to use bodyParser()
app.use(bodyParser.urlencoded({
extended: true
}));
and check by printing the req.body, it work for me and might for u also
the req.body can be accessed also when
content-type:"application/x-www-form-urlencoded"
read this
In your case , your content-type is application/json"
so try changing the content-type to "application/x-www-form-urlencoded"
also url encode the parameters while sending to the server from JS
also solution can be
// fire request
request({
url: url,
method: "POST",
json: true,
headers: {
"content-type": "application/json",
},
body: JSON.stringify(requestData)
}, ...

can't find my json file in req.body when sending it through http post request

I have almost finished adding a new feature on my application trying to pass a json file from angular frontend to node backend via express. The original code come from How do I write a JSON object to file via Node server?. My controller part code look like:
var app = angular.module('myApp',[]);
app.controller('myCtrl',function ($scope, $http){
$scope.saveImage = function(){
var data = JSON.stringify(canvas);
debugger;
$http({
url: 'http://localhost:8080',
method: "POST",
data: data,
header: 'Content-Type: application/json'
});
}
});
I can see from developer tool that the json string "data" do have been created and has lots of things in it in my controller front end. But while I am passing it to node side, I can't get anything from req.body.
Here is my backend code:
// set up
var express = require('express');
var app = express();
var fs = require('fs');
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({extended: false}));
var saveCount = 1;
//functions
// application -------------------------------------------------------------
app.use(express.static('./public'));
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.post('/', function (req, res) {
fs.writeFile(__dirname+"/save/post"+saveCount.toString()+".json", req.body, function(err) {
if(err) {
return console.log(err);
}
res.send('The file was saved!');
});
saveCount++;
});
//listen
app.listen(8080, function () {
console.log('Example app listening on port 8080!');
});
Every time when I check my psot.json files, it only have [object Object]
I have exactly no idea what is happening here.
A few things:
You don't need to call JSON.stringify() on your data object. Just pass the object to $http as is.
You need to pass bodyParser.json() not bodyParser.urlencoded().
JSON.stringify() should be called before you try to write to your file.
Your code should look like:
var app = angular.module('myApp',[]);
app.controller('myCtrl',function ($scope, $http){
$scope.saveImage = function(){
debugger; // What does this do?
$http({
url: 'http://localhost:8080',
method: "POST",
data: canvas,
header: 'Content-Type: application/json'
});
}
});
And
// set up
var express = require('express');
var app = express();
var fs = require('fs');
var bodyParser = require("body-parser");
app.use(bodyParser.json());
var saveCount = 1;
//functions
// application -------------------------------------------------------------
app.use(express.static('./public'));
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.post('/', function (req, res) {
fs.writeFile(__dirname+"/save/post"+saveCount.toString()+".json", JSON.stringify(req.body), function(err) {
if(err) {
return console.log(err);
}
res.send('The file was saved!');
});
saveCount++;
});
//listen
app.listen(8080, function () {
console.log('Example app listening on port 8080!');
});
That [object Object] means that your object is actually making it to the server and being parsed properly, that's just the representation of that object. You really don't need to stringify on the front end, however. $http will handle sending the object for you, you are just creating extra work for your application. And while bodyParser may be picking up the post data (possibly because of how you've handled it on the front end), what you really want is for bodyParser to parse it as a JSON object with the .json() method, because that's what it is.
If you don't want to go through all of that, you could keep things as you have it now and change your Content-Type to application/text or similar so that it's not parsed as an object when it gets to the server.

Simple way of client-server communication in NodeJS

I found a very useful code snippet on GitHub that can provide simple server-client communication in NodeJS.
After some minor formatting, my code looks like this:
The client (Jade + Javascript)
head
title jsonp test
script(src='http://code.jquery.com/jquery-1.6.2.min.js')
script(type='text/javascript').
$(function () {
$('#select_link').click(function (e) {
e.preventDefault();
console.log('select_link clicked');
var data = {};
data.title = "title";
data.message = "message";
$.ajax({
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
url: 'http://localhost:7776/domaintest',
success: function (data) {
console.log('success');
console.log(JSON.stringify(data));
}
});
});
});
body
#select_div
a#select_link(href='#') Test
The server (Javascript)
var express = require('express');
var app = express.createServer();
app.use(express.bodyParser());
app.post('/domaintest', function(req, res){
var obj = {};
console.log('body: ' + JSON.stringify(req.body));
res.send(req.body);
});
app.listen(7776);
Route defined to the client (I was told it's unnecessary for the server as app.post serves the purpose)
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;
The result is a simple text reading "Test" that can be clickable. When I click, the actual events should happen as far as I read it out from the code, but insted browser says POST http://localhost:7776/domaintest 404 (Not Found) in jquery-1.6.2.min.js:18. To be very precise, the error occures in $.ajax, according to the debugger.
Since the jQuery code is practically unreadable because of the formatting (not judging, it might have its reason), I need your help. What's the possible source of the error? Did I forget mentioning something?
Change your server.js file to this. I havent tested the code but this should work.
var express = require('express');
var app = express.createServer();
var router = express.Router();
app.use(express.bodyParser());
router.post('/domaintest', function(req, res, next) {
var obj = {};
console.log('body: ' + JSON.stringify(req.body));
res.send(req.body);
});
app.listen(7776);
You can read this for more information http://adrianmejia.com/blog/2014/10/01/creating-a-restful-api-tutorial-with-nodejs-and-mongodb/
I think this is because your calling body-parser incorrectly. Body parser isn't part of express so you can't do express.bodyParser.
You need to include it like so:
var bodyParser = require('body-parser);
app.use(bodyParser.urlencoded({ extended: false }))
After some research and outside help, I've found the solution.
For domaintest, there was a route defined, which is almost identical to the one I defined for the client. Well, to the domaintest route, I had to add the next function call, right after router.get:
router.post('/', function(req, res) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({data: 'asd'}));
});
The so-called server code above is practically unused and unnecessary; domaintest serves as a server.

How do I send a file from postman to node.js with multer

Windows
Express 4.12.4
Multer 1.0.1
Node v0.10.22
I'm trying to send a file to my node.js server using postman.
I'm attempting to follow the readme here
Here's what I'm sending with postman:
POST /ingest HTTP/1.1
Host: localhost:3000
Cache-Control: no-cache
Postman-Token: 69dd2497-2002-56ed-30a4-d662f77dc0b0
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Here's what it looks like:
Here's what it's hitting on node.js
var Ingest = require('../controllers/ingest.js');
var multer = require('multer');
var upload = multer({ dest: 'uploads/',fileFilter:function(req,file,cb){
console.log('file is',file)
cb(null,true);
}
});
module.exports = function (app) {
app.post('/ingest', upload.single('test'), function(req, res, next) {
console.log(req.body);
console.log(req.file);
Ingest.ingestData()
.then(function (response){
return res.status(200).json(response);
});
});
}
When I hit this route with postman I get {} for req.body and undefined for req.file.
What am I doing wrong?
Here's where I initialize the app that gets passed in to the route file:
var express = require('express');
var app = express();
var http = require('http');
var cfg = require('./config')();
var passport = require('passport');
var cors = require('cors');
var bodyParser = require('body-parser');
app.set('port', process.env.PORT || cfg.port);
var corsOptions = {
origin: "*",
allowedHeaders: ['Content-Type', 'Authorization', 'Accept', 'x-reset-token', 'x-invite-token', 'x-api-key', 'x-www-form-urlencoded'],
credentials: true
};
app.use(cors(corsOptions));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(passport.initialize());
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
Maybe something in there is doing it?
Edit:
I've even tried
var Ingest = require('../controllers/ingest.js');
var multer = require('multer');
var upload = multer({ dest: 'uploads/',fileFilter:function(req,file,cb){
console.log('file is',file)
cb(null,true);
}
}).single('csv');
module.exports = function (app) {
app.post('/ingest', function(req,res){
upload(req, res, function(err) {
if(err){
console.log(err);
}
console.log(req.body);
console.log(req.file);
Ingest.ingestData()
.then(function (response){
return res.status(200).json(response);
});
});
});
}
And that didn't help. It doesn't log anything for err
Just remove header Content-Type:application/x-www-form-urlencoded from the postman.
In Postman screenshot, the file field name is missing. The key should be csv since Multer accepts single file with that name.
This would help others like me who are searching for a similar answer.
I used a curl request instead of Postman.
curl -v -F csv=#file.csv http://localhost/url
There seems to be an issue with Postman.
https://github.com/expressjs/multer/issues/317
I also have this issue when I use Postman to send file using form-data. The attribute req.file or req.files is always undefined. If anyone has used Postman and was able to retrieve the file using req.file or req.files, please comment.
Updating from Postman version 5.5.3 to version 8.0.7. solved the issue for me. Maybe related to this problem fixed in version 7.
Multer looks for the file named 'single'. So if you add the key as 'single' in postman form-data it should work

Categories

Resources