I'm trying to make a post request passing json data. When the request arrives on my express server, it does not have a body. What am I doing wrong?
const http = require('http');
const req = http.request({
hostname: 'localhost',
port: 8080,
path: '/',
method: 'POST'
}, (res) => {
res.on('end', () => {
//
});
});
req.write(JSON.stringify({ something: 'something' }));
req.end();
const express = require('express');
const app = express();
app.use(express.json());
app.post('/', (req, res) => {
console.log(req.body); // undefined
res.send();
});
app.listen(8080);
I have to use the http library of nodejs.
You should:
Move the line where you register the JSON parsing middleware so it appears before the line where you register the / handler. Handlers are called in order so with your current approach, the / will fire and end the chain without reaching the middleware.
Add a Content-Type: application/json request header to the client-side code so that the body parser will not skip over it because it doesn't recognise the (un)declared data type.
8bitIcon could be right. This behavior could be the result of not using a middle ware that parses the body of your request. Check out this post, might help you to solve the problem.
Thank you.
Related
I try to use Postman for generating some post transaction of my web but when I check the post method of my code it print the empty {} and add the empty {} to my list. I try to use middleware but the problem is still occurring.
This is my code.
// my code at restaurant.js
const express = require("express");
const router = express.Router();
const restaurants = require("../data")
router.get("/",(req,res) =>{
res.json(restaurants);
}
)
router.get("/:id",(req,res) =>{
const restaurantid = Number.parseInt(req.params.id,10);
const restaurant = restaurants.find((restaurant) => restaurant.id === restaurantid);
res.json(restaurant);
})
router.post("/",(req,res)=>{
console.log(req.body);
new_restaurant = req.body;
restaurants.push(new_restaurant);
res.json(new_restaurant);
}
)
module.exports = router;
//my code at index.js
const express = require("express");
const app = express();
const router = express.Router();
const restaurantsRouter = require("./routes/restaurants.js");
// Middleware
app.use(express.json());
app.use(express.urlencoded({extended:false}));
// Routes
app.use("/apis/restaurants",restaurantsRouter);
app.get("/",(req,res)=>{
res.send("<h1>Hello Express</h1>");
});
app.listen(3000,()=> {
console.log("Listening to port 3000");
})
module.exports = router;
The general reasons for an empty req.body on an incoming POST request are as follows:
You are failing to send the body properly with whatever client is sending the request.
You are failing to set the right content-type with the request that matches the type of the body data you are sending. If you're sending JSON, then you will need to make sure the incoming request has the content-type application/json.
You don't have the right middleware installed or working properly that will match the incoming content-type, read the body from the incoming stream, parse it and put the parsed results in req.body.
The middleware for parsing that content-type is not registered before your route handler in Express.
Some other middleware is "eating" the body before your middleware so the body is empty when it gets to your JSON middleware.
So, you will need to go through your POST request and eliminate each of these possibilities until you find the problem.
I am using Express and body-parser middleware to process incoming requests. On the front end, I have a form that's just a hidden input and a submit button (written in Pug):
form(notes="saveNotesForm" action=`/lessons/${lesson._id}/notes` method="POST" enctype="application/x-www-form-urlencoded")
input(type="hidden" id="hiddenNotes" name="hiddenNotes" alt="Notes Copy" value="test").notesHidden
input(type="submit" name="saveNotes" alt="Save Notes" value="Save")
On the backend, I have the Express app using body-parser:
const bodyParser = require('body-parser');
// ...
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
And the route processing the incoming request:
router.post('/lessons/:lessonID/notes', lessonController.updateNotes);
// ... and in lessonController:
exports.updateNotes = async (req, res) => {
console.log('updateNotes request received');
console.log(req.body);
res.status(200).json({ status: 'success' });
}
When I try to use req.body in updateNotes, the body is an empty object, but should at least have the property hiddenNotes with the value "test". Please comment if you have any questions or think you see the problem!
[UPDATED]
This was a silly mistake, I forgot I had written a separate event handler for when this form gets submitted - it just took me posting on SO before I went through all of my code :) The event handler uses axios and looks like this:
const SaveNotesButton = $('form.saveNotes');
SaveNotesButton.on('submit', ajaxSaveNotes);
function ajaxSaveNotes(e) {
e.preventDefault();
axios
.post(this.action)
.then(res => {
console.log(res.data);
})
.catch(console.error);
}
Unfortunately, when making posts with axios, you need to include the data in an object like this, or else it won't be included in the request:
const SaveNotesButton = $('form.saveNotes');
SaveNotesButton.on('submit', ajaxSaveNotes);
function ajaxSaveNotes(e) {
e.preventDefault();
axios
.post(this.action, { notes: this.children.hiddenNotes.value }) // Data added here
.then(res => {
console.log(res.data);
})
.catch(console.error);
}
Have to tried querying your end point using Postman or something similar?
There could be one possible explanation for why your req.body is undefined. Are you sure your app.use(bodyParser.json()) and app.use(bodyParser.url... are written before your app.use('***', router) lines? If you put the body parser middleware AFTER your router middleware it essentially won't get called because middleware are called in the order they are put in app.use. So you should place your bodyParser before all your router logic. BodyParser middleware then calls all the other middleware (with the req.body populated) that come after it including all your router level middleware.
Hope it helps!
Not sure how you are defining your routes but I would expect a post route to look like the following:
const express = require('express');
const app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.post('/lessons/:lessonID/notes', (req, res) => {
// now pass the req object to your function
lessonController.updateNotes(req);
});
You need to pass the req object to your function to be able to access req.body...
I have an Express server listening on a Unix Domain Socket. I'm making an http request like so:
const requestOptions = {socketPath, method, path, headers, _custom: {foo: () => 'bar'}}
http.request(requestOptions, responseCb)
And want to use _custom in my Express route handlers
app.get('/', (req, res) => {
console.log(req._custom)
})
Is this possible?
EDIT: _custom is an object with functions.
EDIT: The answer I marked as correct is the best solution I could find, however it does not allow sending of objects (which is what I really want).
You can add _custom to your req object by adding custom middleware in your Express server prior to your routes that need to use req._custom.
app.use((req, res, next) => {
if (req.get('X-Custom-Header')) {
// add custom to your request object
req._custom = req.get('X-Custom-Header');
}
return next();
});
On the client side you can add the custom header
let headers = {
'X-Custom-Header': 'my-custom-value'
};
const requestOptions = {socketPath, method, path, headers};
http.request(requestOptions, responseCb)
This seems like it should be a fairly simple question, but I'm having a really hard time figuring out how to approach it.
I'm using Node.js + Express to build a web application, and I find the connect BodyParser that express exposes to be very useful in most cases. However, I would like to have more granular access to multipart form-data POSTS as they come - I need to pipe the input stream to another server, and want to avoid downloading the whole file first.
Because I'm using the Express BodyParser, however, all file uploads are parsed automatically and uploaded and available using "request.files" before they ever get to any of my functions.
Is there a way for me to disable the BodyParser for multipart formdata posts without disabling it for everything else?
If you need to use the functionality provided by express.bodyParser but you want to disable it for multipart/form-data, the trick is to not use express.bodyParser directly. express.bodyParser is a convenience method that wraps three other methods: express.json, express.urlencoded, and express.multipart.
So instead of saying
app.use(express.bodyParser())
you just need to say
app.use(express.json())
.use(express.urlencoded())
This gives you all the benefits of the bodyparser for most data while allowing you to handle formdata uploads independently.
Edit: json and urlencoded are now no longer bundled with Express. They are provided by the separate body-parser module and you now use them as follows:
bodyParser = require("body-parser")
app.use(bodyParser.json())
.use(bodyParser.urlencoded())
If the need for body parsing depends only on the route itself, the simplest thing is to use bodyParser as a route middleware function on only the routes that need it rather than using it app-wide:
var express=require('express');
var app=express.createServer();
app.post('/body', express.bodyParser(), function(req, res) {
res.send(typeof(req.body), {'Content-Type': 'text/plain'});
});
app.post('/nobody', function(req, res) {
res.send(typeof(req.body), {'Content-Type': 'text/plain'});
});
app.listen(2484);
When you type app.use(express.bodyParser()), almost each request will go through bodyParser functions (which one will be executed depends on Content-Type header).
By default, there are 3 headers supported (AFAIR). You could see sources to be sure. You can (re)define handlers for Content-Types with something like this:
var express = require('express');
var bodyParser = express.bodyParser;
// redefine handler for Content-Type: multipart/form-data
bodyParser.parse('multipart/form-data') = function(req, options, next) {
// parse request body your way; example of such action:
// https://github.com/senchalabs/connect/blob/master/lib/middleware/multipart.js
// for your needs it will probably be this:
next();
}
upd.
Things have changed in Express 3, so I'm sharing updated code from working project (should be app.useed before express.bodyParser()):
var connectUtils = require('express/node_modules/connect/lib/utils');
/**
* Parses body and puts it to `request.rawBody`.
* #param {Array|String} contentTypes Value(s) of Content-Type header for which
parser will be applied.
* #return {Function} Express Middleware
*/
module.exports = function(contentTypes) {
contentTypes = Array.isArray(contentTypes) ? contentTypes
: [contentTypes];
return function (req, res, next) {
if (req._body)
return next();
req.body = req.body || {};
if (!connectUtils.hasBody(req))
return next();
if (-1 === contentTypes.indexOf(req.header('content-type')))
return next();
req.setEncoding('utf8'); // Reconsider this line!
req._body = true; // Mark as parsed for other body parsers.
req.rawBody = '';
req.on('data', function (chunk) {
req.rawBody += chunk;
});
req.on('end', next);
};
};
And some pseudo-code, regarding original question:
function disableParserForContentType(req, res, next) {
if (req.contentType in options.contentTypes) {
req._body = true;
next();
}
}
Within Express 3, you can pass parameter to the bodyParser as {defer: true} - which in term defers multipart processing and exposes the Formidable form object as req.form. Meaning your code can be:
...
app.use(express.bodyParser({defer: true}));
...
// your upload handling request
app.post('/upload', function(req, res)) {
var incomingForm = req.form // it is Formidable form object
incomingForm.on('error', function(err){
console.log(error); //handle the error
})
incomingForm.on('fileBegin', function(name, file){
// do your things here when upload starts
})
incomingForm.on('end', function(){
// do stuff after file upload
});
// Main entry for parsing the files
// needed to start Formidables activity
incomingForm.parse(req, function(err, fields, files){
})
}
For more detailed formidable event handling refer to https://github.com/felixge/node-formidable
I've faced similar problems in 3.1.1 and found (not so pretty IMO) solution:
to disable bodyParser for multipart/form-data:
var bodyParser = express.bodyParser();
app.use(function(req,res,next){
if(req.get('content-type').indexOf('multipart/form-data') === 0)return next();
bodyParser(req,res,next);
});
and for parsing the content:
app.all('/:token?/:collection',function(req,res,next){
if(req.get('content-type').indexOf('multipart/form-data') !== 0)return next();
if(req.method != 'POST' && req.method != 'PUT')return next();
//...use your custom code here
});
for example I'm using node-multiparty where the custom code should look like this:
var form = new multiparty.Form();
form.on('file',function(name,file){
//...per file event handling
});
form.parse(req, function(err, fields, files) {
//...next();
});
With express v4, and body-parser v1.17 and above,
You can pass a function in the type of bodyParser.json.
body-parser will parse only those inputs where this function returns a truthy value.
app.use(bodyParser.json({
type: function(req) {
return req.get('content-type').indexOf('multipart/form-data') !== 0;
},
}));
In the above code,
the function returns a falsy value if the content-type is multipart/form-data.
So, it does not parse the data when the content-type is multipart/form-data.
throw this is before app.configure
delete express.bodyParser.parse['multipart/form-data'];
How do i let node.js act as a proxy and forward all requests sent from one server to another server but stripping /couchdb/ from the url path so that for example POST /couchdb/mydatabase will be POST /mydatabase. And when it receives the response it should send it to the first server.
All I have done is this (using express) to get all requests where the URL path starts with /couchdb/
app.all(/^\/couchdb\/(?:.)*/, function(req, res) {
});
Could someone guide me through. Thanks
have a look at node-http-proxy. you can use it like this:
var http = require('http'),
httpProxy = require('http-proxy');
httpProxy.createServer(function (req, res, proxy) {
// Put your custom server logic here (eg rewrite url/header,...)
proxy.proxyRequest(req, res, {host: 'localhost', port: 9000});
}).listen(8000);