I'm still reasonably new to the whole node thingie, so please forgive me if this is rampantly stupid, but:
If I call query()
on a node-mysql client object, I can no longer get the body of a request object from within my web app (express).
my basic POST / PUT pattern requests requiring user auth is:
_db_client = connect_to_db_server();
app.post("/some/path", function (req, res) {
_db_client.query("SELECT * FROM Users WHERE username = ?",
[ http_basic_auth.username ], function (err, results) {
if (err != null || resp == null) {
res.send("AUTH FAILURE: sorry, you can't do that", 403);
} else {
get_request_body(req, function (body) {
do_something();
res.send("yay, I'm happy", 200);
});
}
});
});
Now, the problem is that the get_request_body function simply never comes back. It seems as though it's just "blocked" on teh request object.
Here is a sample program:
var express = require('express'),
mysql = require('mysql');
var MySQLClient = mysql.Client;
var client = new MySQLClient();
client.user = 'root';
client.password = '';
client.connect(function(err, res) {
client.query("USE Gazelle", function (qerr, qresp) {
});
});
var app = express.createServer( );
app.use(express.bodyParser());
app.post("/test", function (req, res) {
client.query('SELECT * FROM Users', function (err, results) {
get_request_body(req, function (body) {
console.log("wooo");
console.log(body);
res.send("cool", 200);
});
});
});
app.listen(8080);
function get_request_body (req, callback) {
if (req.rawBody != undefined) {
callback(req.rawBody);
} else {
var data = '';
req.setEncoding('binary');
req.on('data', function(chunk) {
data += chunk;
});
req.on('end', function() {
callback(data);
});
}
}
The trick: It only fails if I'm using multipart form POST data, not regular POST data:
curl -u un:pw -X POST -d ' { "cat" : "meow" }' http://localhost:8080/test
works
curl -u un:pw -X POST -F "[email protected]" http://localhost:8080/test
locks up and never returns. I've seen the same error with connect-form and multipart-js. Kind of stumped here now.
Am i a complete idiot? Is this not the correct way of doing things?
I think by the time you add your end
listener to the request object, the end
event has already fired. You need to add your IO event listeners to the req
object immediately in the main app.post
function scope, not in an async callback when your DB query returns. Here's a version with some log statements that show the sequence of events causing this issue. The req.emit('end');
at the bottom is just a hack to prove why the request is locking up. Your end
event handler never gets called, but synthesizing a duplicate end
event does allow the request to complete (but the body has not been properly parsed).
var express = require('express');
var app = express.createServer( );
app.use(express.bodyParser());
app.post("/test", function (req, res) {
req.on('data', function(){
console.log("data fired but your listener is not yet added");
});
req.on('end', function() {
console.log('end fired but your listener is not yet added');
});
setTimeout(function() { //Simulating your async DB query
console.log("setTimeout finished and fired callback");
get_request_body(req, function (body) {
console.log("wooo");
console.log(body);
res.send("cool", 200);
});
}, 50);
});
app.listen(8081);
function get_request_body (req, callback) {
if (req.rawBody != undefined) {
console.log('express.bodyParser parsed it already');
callback(req.rawBody);
} else {
console.log('get_request_body going to parse because ' + req.rawBody);
var data = '';
req.setEncoding('binary');
req.on('data', function(chunk) {
console.log('get_request_body got data event');
data += chunk;
});
req.on('end', function() {
console.log('get_request_body parsed it');
callback(data);
});
req.emit('end');//BUGBUG
}
}