nodejs proxy timing and async behavior - node.js

I have a question about the code below:
I would need a confirmation that all the processing done in proxyRes event
will be done asynchronously and all processing time in it won't affect
the proxying time.
Thank you in advance for help in this
var server = http.createServer(function (req, res) {
console.time();
var proxy = httpProxy.createProxyServer();
proxy.web(req, res, {
target: 'https://gdev.sserver.be/api/host1/account',
});
console.timeEnd();
proxy.on('proxyRes', function (proxyRes, req, res) {
//console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
proxyRes.on('data', function (chunk) {
console.log('resp => ' + chunk);
connection.query('INSERT INTO test SET ?', {content: chunk}, function(err, result) {
if (err) throw err;
console.log('writing in db');
});
});
proxy.close();
proxy = null;
});
}).listen(3000);

Yes, the contents of your proxyRes handler appear to be asynchronous. The proxy will occur while the database query is still doing what it needs to do, so you're right that it won't affect proxying time.

Related

req.on('end fired but not req.on('data

My Nodejs req.on('data') not trigger, but req.on('end') works. I'm learning Nodejs and I don't know how to fix it.
My Nodejs file:
let routes = {
'GET': {
'/': (req,res) => {
fs.readFile('./public/index.html', (err, html) => {
if(err) throw err;
res.writeHead(200, {'Content-type': 'text/html'});
res.write(html);
res.end();
});
}
},
'POST': {
'/api/login': (req, res) => {
let body = '';
req.on('data', data => {
console.log('req data fired!');
body += data;
});
req.on('end', () => {
console.log('req end fired!')
res.end();
})
}
}
}
function router(req, res) {
let baseURL = url.parse(req.url, true);
let resolveRoute = routes[req.method][baseURL.pathname];
if(resolveRoute != undefined) {
resolveRoute(req, res);
}
}
http.createServer(router).listen(3000, () => console.log('Server running in port 3000'));
How to fix the req.on('data') triggering?
If the data event doesn't fire, but the end event does, then it's because there is no actual body data in the POST request.
With your exact code, the only way I could reproduce what you describe is when the POST body was empty and there was no data there to read. If, for example, you are submitting a form in the browser and there are no elements in the form with a name attribute, no data will be sent with the request.
As soon as I made sure there was some data in the POST request, then the data event fires and it presents a Buffer with the data in it.

HTTPS Request in a Node express route

I tried to get a result of a https request in a route in node express but it fails with the reason: connect ETIMEOUT. Any Idea where I'm wrong?
router.get("/", async (req, res) => {
try {
result = await https.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY');
console.log(result);
res.send(result);
}
catch (err) {
console.log(err);
}
});
EDIT:
The URL is valid and does return something when pasted in browser,
Other endpoints in my API work fine, but they don't have a http request thought. They look like this i.e:
router.get("/", (req, res) => {
try {
res.sendFile("\\\\abc.local\\a$\\b$\\xyz\\001-005-877.pdf");
}
catch (err) {
res.status(500).json({ err: err.toString() });
}
});
EDIT:
For completion:
I had a typo in my index.js/ routing (app.use("/test", require("./routes/test")); which caused the timeout.
Then used this code:
router.get("/", (req, res) => {
request('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY', function (error, response, body) {
console.log('error:', error);
console.log('statusCode:', response && response.statusCode);
console.log('body:', body);
})
});
I used the module 'request'. as Dijkstra suggested and even though his code (for express default http requests) wasn't working for me, he still provided everything needed to solve the problem, so Thank you.
I believe this is not how https.get() works. Documentation is here.
Possible implementation:
router.get("/", async (req, res) => {
https.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY', (result) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
const data = '';
result.on('data', function (chunk) {
body += chunk;
});
result.on('end', () => {
res.send(JSON.parse(data));
});
}).on('error', (e) => {
console.error(e);
});
});
This is pretty complex code to perform such typical task. That is why there are popular packages to handle all the complex part behind the scene. I prefer to use Request.

Error: Can't set headers after they are sent in loop multiple request

i'm beginner at nodejs, i got a problem when request multiple url in a loop then i render it.
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:)
router.get('/', function(req, res, next) {
setInterval(function(){
request(url1,function (error,response,body) {
var data1 = JSON.parse(body);
request(url2+data1.access_token,function (error,response,body) {
var data_info = JSON.parse(body);
//error when it render
res.render('index', {data_info : data_info});
})
})
},5000);
});
That's not exactly a loop, I understand you mean that you call the same function repeteadly with setInterval().
Once you've sent your first response with res.render(), which finishes the response process for that request, subsequent attempts to use that res object fail.
If you want to send data to the client in 5 seconds interval you should probably either look into websockets or pass the setInterval() calls to the client so it polls your server each 5 seconds, in which case your server code could be changed to:
router.get('/', (req, res) => {
request(url1, (error, response, body) => {
const data1 = JSON.parse(body);
request(`${url2}${data1.access_token}`, (error, response, body) => {
const data_info = JSON.parse(body);
res.render('index', { data_info });
});
});
});
You can make use of Async Module
const async = require('async');
router.get('/', function (req, res, next) {
async.waterfall([
function(callback) {
request(url1, function (error,response,body) {
if(err) {
callback(err)
}else {
var data1 = JSON.parse(body);
callback(data1)
}
})
},
function(data1, callback) {
request(url2+data1.access_token, function(error,response,body) {
if(err) {
callback(err)
}else {
var data_info = JSON.parse(body);
callback(null, data_info)
}
})
}
], function(err, result) {
if(err) {
res.json({success: false, error: err, message: "Something went wrong.!"})
}else {
res.render('index', {
data_info : result
});
}
})
})

Node.js get response outside app.post

I want get response, to save cookie.. I used express on node.js
app.post('/', function (req, res) {
res.setHeader("Set-Cookie", ["dok=javascript"]);
})
I want to do outside of app.post - real time used socket.io
for example:
socket.on('Login-clicked', function(data) {
if(data == ok) {
res.setHeader("Set-Cookie", ["dok=javascript"]);
}
});
How can i do?
I think what you are trying to do here is access res in socket.on('Login-clicked') event.To do that first make res global.
global.res={};
app.post('/', function (req, res) {
global.res=res;
});
socket.on('Login-clicked', function(data) {
if(data == ok) {
global.res.setHeader("Set-Cookie", ["dok=javascript"]);
}
});

Invoking an asynchronous method inside a middleware in node-http-proxy

I'm trying to create a proxy with node-http-proxy in Node.js that checks whether a request is authorized in a mongodb.
Basically, I created a middleware module for the node-http-proxy that I use like this:
httpProxy.createServer(
require('./example-middleware')(),
9005, 'localhost'
).listen(8005)
What the middleware module does is using mongojs to connect to mongodb and run a query to see if the user is authorized to access the resource:
module.exports = function(){
// Do something when first loaded!
console.log("Middleware loaded!");
return function (req, res, next) {
var record = extractCredentials(req);
var query = -- Db query --
//Debug:
log("Query result", query);
db.authList.find(query).sort({
"url.len": -1
}, function(err, docs){
console.log(docs);
// Return the creator for the longest matching path:
if(docs.length > 0) {
console.log("User confirmed!");
next();
} else {
console.log("User not confirmed!");
res.writeHead(403, {
'Content-Type': 'text/plain'
});
res.write('You are not allowed to access this resource...');
res.end();
}
});
}
}
Now the problem is that as soon as I add the asynchronous call to mongodb using mongojs the proxy hangs and never send the response back.
To clarify: on a "User not confirmed" everything works fine and the 403 is returned. On a "user confirmed" however I see the log but the browser then hangs forever and the request isn't proxied.
Now, if I remove the "user confirmed" and next() part outside of a callback it does work:
module.exports = function(){
// Do something when first loaded!
console.log("Middleware loaded!");
return function (req, res, next) {
var record = extractCredentials(req);
var query = --- query ---
console.log("User confirmed!");
next();
}
but I can't do that since the mongojs query is meant (rightfully I guess) to be executed asynchronously, the callback being triggered only when the db replied...
I also tried the version without using a middleware:
http.createServer(function (req, res) {
// run the async query here!
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
}).listen(8001);
But that did not help either...
Any clue? Note that I'm new to node.js so I suspect a misunderstanding on my side...
Found the answer, actually the catch is that the request needs to be buffered:
httpProxy.createServer(function (req, res, proxy) {
// ignore favicon
if (req.url === '/favicon.ico') {
res.writeHead(200, {
'Content-Type': 'image/x-icon'
} );
res.end();
console.log('favicon requested');
return;
}
var credentials = extractCredentials(req);
console.log(credentials);
var buffer = httpProxy.buffer(req);
checkRequest(credentials, function(user){
if(user == ...) {
console.log("Access granted!");
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9005,
buffer: buffer
});
} else {
console.log("Access denied!");
res.writeHead(403, {
"Content-Type": "text/plain"
});
res.write("You are not allowed to access this resource...");
res.end();
}
});
}).listen(8005);
Two problems:
You're not calling next(); in the else case of your sort callback.
The second parameter to your sort callback is a Cursor, not an array of documents. As such, docs.length > 0 is never true and the code always follows the else path.

Resources