I have a superstrange error with node.js and express which is driving me nuts for two days now.
I want to display a series of images on my web app. Therefore, I'm sending a GET request from the client to my express API, which then should deliver the image.
It works perfectly with only ONE image per page.
However, if I want to display a series of images, let's say 8 images, ONLY THE LAST IMAGE IS BEING RENDERED! But the order changes occassionaly, sometimes it's the penultimate image that works, it's being shuffled in a complete random order!
But it's not only a problem with images - it's the same behaviour with ALL (async) requests!
For example, if I want to render some usernames to an iframe, I only get the data for the last iframe, all others show mit a 404 error with CANNOT GET.
This is my code on the frontend:
<iframe src="http://127.0.0.1:3000/files/bigThumb/file-version-2017-12-27T11-53-45-647Z-3DnsDX?projectdb=cdu_regierung&companydb=cdu&authsession=supersecrettoken"></iframe>
<iframe src="http://127.0.0.1:3000/files/bigThumb/file-version-2017-12-27T13-08-58-189Z-q52KKd?projectdb=cdu_regierung&companydb=cdu&authsession=supersecrettoken"></iframe>
<iframe src="http://127.0.0.1:3000/files/bigThumb/file-version-2017-12-27T13-08-58-189Z-q52KKd?projectdb=cdu_regierung&companydb=cdu&authsession=supersecrettoken"></iframe>
<iframe src="http://127.0.0.1:3000/files/bigThumb/file-version-2017-12-27T13-08-58-189Z-q52KKd?projectdb=cdu_regierung&companydb=cdu&authsession=supersecrettoken"></iframe>
this is my code in on the server side
app.all('/files/:action/:versionId', async function(req, res) {
try {
var projectName = req.query.projectdb;
var companyName = req.query.companydb;
var authSession = req.query.authsession;
var nano = _nano({url: 'http://127.0.0.1:5984/', cors: true, cookie: 'AuthSession='+ authSession});
var session = await nano.session();
session = session[0];
var username = session.userCtx.name;
res.send(username);
} catch(err) {
return res.status(401).send(err);
}
})
My guess is that it has something to do with ASYNC function in
app.all('/files/:action/:versionId', async function(req, res) {
as I never had this problem with standard sync function(req, res)
What am I doing wrong??
EDIT
I have them same problem with this code below.
app.all('/files/:action/:versionId', function(req, res) {
request('https://jsonplaceholder.typicode.com/posts/1', function (error, response, body) {
res.send(body);
});
It works perfectly with 1 GET, but not with 8 simultaneous GET requests. Also, I'm getting this error in the log:
_http_outgoing.js:494
throw new Error('Can\'t set headers after they are sent.');
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:494:11)
I found the solution - it's a bug caused by the nodejs middleware "express-formidable". The issue is discussed here.
https://github.com/utatti/express-formidable/issues/6
Just use the "formidable" middleware and you're good to go.
This is the code I ended up with.
var formidable = require('formidable');
// init formidable middleware
app.use(function (req, res, next) {
var form = new formidable.IncomingForm({
encoding: 'utf-8',
multiples: false,
keepExtensions: true,
})
form.once('error', console.log)
form.parse(req, function (err, fields, files) {
Object.assign(req, {fields, files});
next();
})
});
Related
I am trying to redirect the user with a post request from the home page after checking if their sessions exist.
This is my home controller file:-
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
if (req.session["Data"] != undefined) {
res.redirect(307, '/Try');
}
else {res.render('home', {pageTitle: "Home"});}
});
module.exports = router;
But it is giving me error- Cannot GET /Try
This is what I'm using in my route file- router.post('/Try', try_controller.Try);
I am using res.redirect(307, '/Try') in another controller file of the same project and it's working. I can't figure out why it's not working here.
I don't think you can redirect a GET as a POST. If you own the /Try route, one option is to add a GET handler for that, then redirect will work.
Otherwise, in your GET route handler for \ you can create a new POST and return the results of that.
const request = require('request')
router.get('/', (req, res, next) => {
if (req.session["Data"] != undefined) {
//res.redirect(307, '/Try');
request.post('/Try', {}, function(err, response, body) {
if (err) return next(err)
return res.status(response.statusCode).send(body);
})
}
else {res.render('home', {pageTitle: "Home"});}
});
The example above an https://github.com/request/request though there are more modern ways of sending POST from express.
This isn't technically "redirecting", so you won't return 307 or 302.
I tried different things but in the end, I added an empty form in my home.pug file and submitted it using js.
JS code -
script.
let ssn = !{JSON.stringify(session)};
data = "Data"
if (ssn[data] != undefined) {document.getElementById('form-id').submit();}
I'm using express to build a simple server.
Everything works, but I'm getting this annoying error in the console every time I try to hard-refresh (cntr + R) my page.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Here is the code:
app.get('/index', (req, res) => {
const filePath = path.join(__dirname, 'public', 'index.html');
console.log(res.headersSent);
res.sendFile(filePath);
});
The console.log(res.headersSent) is there to check that indeed, the headers are NOT set (it logs false every time).
I tried sending a simple JSON instead of a file, and no error occurs:
app.get('/index', (req, res) => {
const filePath = path.join(__dirname, 'public', 'index.html');
console.log(res.headersSent);
res.json({status: 'All good'});
});
The error occurs only when I'm using res.sendFile().
The index.html will request an index.js file once it loads. Maybe that's the issue? But isn't it a different request?
Thank you!
EDIT
I've tried checking for errors in the callback function of sendFile().
It's undefined, even though the console keeps spitting out the "Cannot set headers" error
sendFile is asynchronous function, so you need to send response after the engine reads the file, but json is synchronous instead (that's why it didn't thrown an error for that).
In other words, you need to send the response from the callback, something like this:
app.get('/index', (req, res) => {
const filePath = path.join(__dirname, 'public/index.html');
res.sendFile(filePath, function(err) {
if (err) {
return res.status(err.status).end();
} else {
return res.status(200).end();
}
});
});
For more, read read these:
Node.js Response object (official docs)
Express.js res.sendFile() Function
About Node.js response methods explained in StackOverflow answer
I have a sign up form that I want to re-populate with the user entered data when the form is submitted but has errors in them. I am using express-validator and connect-flash to check / show error messages. I can't seem to figure out a way to pass the original values back to repopulate the field.
Here's my route:
router.post('/edit',
// Input validation
function(req, res, next) {
req.checkBody('username', 'Username cannot be empty').trim().notEmpty();
var errors = req.validationErrors(true);
if (errors) {
req.flash('validation', errors);
res.redirect('/vendor/edit/'));
} else {
//Add to DB
}
});
Here is where I either load the original form, or where it gets redirected to show the form with error messages. :
router.get('/edit', function(req, res) {
res.render('vendor_edit', {
validation: req.flash('validation')[0],
error: req.flash('error')[0],
});
});
However, the form is blank when it gets redirected since my template doesn't have the original values, or I don't know how to access them if they are naturally passed? - I am trying to render in PUG.
This is made possible via this post:
How do I redirect in expressjs while passing some context?
For the lazy, here is the copy and paste of the code from the above link, it worked like a charm for me.
var express = require('express');
var jade = require('jade');
var http = require("http");
var app = express();
var server = http.createServer(app);
/////////////
// Routing //
/////////////
// Move route middleware into named
// functions
function homeCtrl(req, res) {
// Prepare the context
var context = req.dataProcessed;
res.render('home.jade', context);
}
function categoryCtrl(req, res, next) {
// Process the data received in req.body
// instead of res.redirect('/');
req.dataProcessed = somethingYouDid;
return next();
// optionally - Same effect
// accept no need to define homeCtrl
// as the last piece of middleware
// return homeCtrl(req, res, next);
}
app.get('/', homeCtrl);
app.post('/category', categoryCtrl, homeCtrl);
I have the following node-mitm code.
mitm = Mitm();
mitm.on("request", function(req, res) {
const body = req.body; //body is null
})
I feel this has to do with reading node's IncomingMessage events, but I don't know how to do it.
Mitm.js's request handler is just like the one you're used to on Node's side. That is, it doesn't do anything special with req.body and leaves it as a ReadableStream.
You could either get its contents with the classical on("data") pattern:
mitm.on("request", function(req, res) {
req.on("data", function(data) { data == "Hello" })
})
If you want to fake a larger service, I've sometimes used Express to create routes and then pass Express's route handler to Mitm:
var Router = require("express").Router
var router = Router().use(require("body-parser").text())
router.get("/", function(req, res) { req.end() })
mitm.on("request", route.bind(null, router))
function route(router, req, res) {
router(req, res, function(err) {
if (err == null) return
res.writeHead(502)
throw err
})
}
The last example is a summary of the pattern I've also got publicly visible at the Rahvaalgatus open source repository: https://github.com/rahvaalgatus/rahvaalgatus.
Specifically, look at the controller test of https://github.com/rahvaalgatus/rahvaalgatus/blob/6dc91b026d75879cdc552bd2e63f220235b786c0/test/controllers/home_controller_test.js and see the this.router definition at https://github.com/rahvaalgatus/rahvaalgatus/blob/6dc91b026d75879cdc552bd2e63f220235b786c0/test/mitm.js.
I have the following...
var request = require('request');
exports.list = function(req, res){
res.send("Listing");
};
exports.get = function(req, res){
request.get("<URL>", function (err, res, body) {
if (!err) {
res.send(body,"utf8");
}
});
};
This fails with the following....
TypeError: Object #<IncomingMessage> has no method 'send'
How do I do this?
UPDATE tried to use write instead of send but...
/Users/me/Development/htp/routes/property.js:9
res.setHeader('Content-Type', 'text/html');
^
TypeError: Object #<IncomingMessage> has no method 'setHeader'
Also writing out to the console instead works fine.
Problem was with scope of variables, my response output was the same name as the response object I got back in my callback. Changing this around (resp vs res) made it work....
exports.get = function(req, res){
request.get("<url>", function (err, resp, body) {
if (!err) {
res.send(body);
}
});
};
What you are trying to do, is to make Request > Response server. But you are using Request module, that allows to get stuff rather than respond.
What you need is http or better get express.js and use it, as it is straight forward and well popular web framework for exactly what you need.
I wasn't aware OP is using Express. You will encounter a similar error if you attempt to use req.send with the vanilla HTTP module instead of Express.
var http = require('http');
function requestHandler(req, res){
//res.send(200, '<html></html>'); // not a valid method without express
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end('<html><body>foo bar</body></html>');
};
http.createServer(handler).listen(3000);