node.js - how to modiffy response headers - node.js

Platform: node.js + express and request modules (beginner).
HI, I got simply router.get followed by a request and I want to modify the headers it get from external server, and send it to the user that requested the specific data.
router.get('/', function(req, res){
var someUserRequest = request('http://google.com', function(error, resp, body){
if (error){
console.log(error);
}
console.log(resp.headers); //lets assume that there is 'x-content-type-options' that I don't want for example
}
req.pipe(someUserRequest).on('response', function(response){
delete response.headers['x-content-type-options'];
console.log(response.headers); // everything looks fine here - no 'x-content-type-options'
}).pipe(res);
});
module.exports = router;
So it seams that there is no 'x-content-type-options'. However when I check this out in chrome developer tools (network) I can clearly see 'x-content-type-options: nosniff' - even when I clear all history/cache.
So why it's not working? Can somebody explain me where is the error?

I think that you might need to splice the array instead, try putting a test condition before and after you
delete
to see if
['x-content-type-options']
exists in response.headers.
If it does then you can probably splice instead.
Read more on delete here

Related

how to pass data and redirect in express

My code is
main.post('/userlist', function(req, res, next) {
// where did you get this?
// var db = req.db;
var query = connection.query("SELECT name,zaman,giriscikis FROM giriscikis where date_format(zaman,'%Y-%m-%d') between ? and ?", [req.body.bas, req.body.bitis], function(err, result) {
if (err) throw err;
console.log(result);
res.send(httpResponse(result));
return res.redirect('/zamansorgu');
//console.log(req.body.bas)
//console.log(req.body.bitis)
});
});
I want to fecth data from database and redirect to same page in the code(zamansorgu.html)
But I get an error
Cannot set headers after they are sent to the client
How can I solve this problem
thank you for your helps
You are attempting to send back JSON data and redirect to a different page. That's not possible. Each endpoint request can have one response, not more. You can either send back the data, or redirect. That's because redirecting really does send back data too (the html of the new target page).
Think about it from the caller's point of view. If it did allow this how would it work? If someone uses this link from a browser should the browser show the JSON data you returned, or should it take the user to the new page?
The error is saying "hey, I already sent back data. I can't redirect now because we are already down the path of returning some JSON".
If you want to use the data to format the output that can be done, or if you want to redirect to a new location and pass the data in the url, that's also possible. Consider code like this:
main.post('/userlist', function(req, res, next) {
// var db = req.db;
var query = connection.query("SELECT name,zaman,giriscikis FROM giriscikis where date_format(zaman,'%Y-%m-%d') between ? and ?", [req.body.bas, req.body.bitis], function(err, result) {
if (err) return next(err);
if (result.urlparam) {
// this builds a new url using the query value
const nextUrl = `/zamansorgu?param=${result.urlparam}`;
return res.redirect(nextUrl);
}
else {
// this builds html here
const html = `<html><body><h1>${result.title}</h1></body></html>`;
return res.send(html);
}
});
});
I also ran into this, in my case it was quite a deceptive little bug. A node-inspector session helped me pinpoint the problem quickly however. The problem in my case was pretty bone-headed, the res.end call in the sample below is the offending line.
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify(someObject));
someObject did not exist after a refactor and that was causing a ReferenceError to get thrown. There is a try-catch in Router.prototype._dispatch that is catching the ReferenceError and passing it into next
res.status(301).redirect(`/zamansorgu?name=${"John"}&email=${"john#email.com"}`)
So, this is something I explored but it will be dependent on the structure of your application. You could always pull the data out using query params and hydrate your application.

request.get() - if url not found

So I want to end the request if the user tries to fetch a url which does not work.
This works:
var remote = "https://storage.googleapis.com/ad-system/testfolder/OUTOFAREA.mp3";
var streama = request.get(remote);
however lets say the following mp3 does not exisit
https://storage.googleapis.com/ad-system/testfolder/playme.mp3
When the request.get('https://storage.googleapis.com/ad-system/testfolder/playme.mp3'); tries and fetch the file it will return a 404 error. What I want to do is file not found I want to run res.end();
Any ideas?
you can write like ### request('endpoint url goes here', { json: true }, (err, res, body) => {
if (err) { // keep your business logic here}
}) ######
hope it helps
I doesn't know about this Cloud Storage but even the link isn't accessible so I recommend you check if something is wrong in this service or if you require some special keys or something else to access the content or the service. Then, check your code or use a library that can handle your requirements (if available).
If I found something, I'll let you know :)
EDIT: I can access to https://storage.googleapis.com/ad-system/testfolder/Video/30%20Second%20Timer-0yZcDeVsj_Y.f137.mp4
You could do
app.get("*",(req,res)=> {
res.end()
});
and insert it just before your 404 handler however, I would challenge why that ever might be a good idea. If it's literally so you scan skip checking the return code I really advice you to think twice if thats something you wanna be doing atleast do:
app.get("*",(req,res)=> {
res.status(404)
res.end()
});

How to set Routes for APIs

I am building an API to manage meetups with nodeJS. I have build an endpoint with the route "/meetups/:id/" to fetch a specific meetup record by its id. And then I want to fetch all the upcoming meetup records and I tried to use "/meetups/upcoming/" but when I query it, I get the not found error (404). It seems like the second route is not recognised.
Here is the code defining the two routes
the request from postman
Any help on how can I handle that?
Thanks.
Route is '/api/v1/meetups/upcoming/all'. Move res.status outside the map function.
EDIT: you'll have to change the route which has to be different from api/v1/meetups/:id. Reason is when route '/api/v1/meetups/upcoming' is requested express sees it as the same route as before and takes 'upcoming' as the parameter.
app.get("/api/v1/meetups/upcoming/all", function(req, res) {
var today = new Date();
var upcomings = db.meetups.map(function(meetup) {
if(meetup.happeningOn > today) {
return meetup;
}
});
res.status(200).send({
status: 200,
data: upcomings
});
});
You need to move the res.status piece outside of the const upcomings definition.

How do I make sure a promise has been returned before responding to an incoming request (Swagger/Express)

I'm trying to write a simple Swagger API that will allow me to sync a couple of systems on demand. The syncing is one way, so basically the end goal will be to send a request to both system, see what's new/changed/removed on the origin, then update the destination. I've been trying to do this using node.js instead of Java, to which I'm more used to, as a learning experience, but I'm really having a hard time figuring out a key issue due to the async nature.
As a test, I constructed a simple Express node.js app on IntelliJ, where in one of the routes I'm calling a function exported from a different file and trying to get the response back. Unfortunately, this isn't working so well. What I've done is this:
getit.js - (this goes to the Ron Swanson generator to get a quote)
const rp = require('request-promise');
async function dorequest() {
const response = await rp(uri);
return Promise.resolve(response);
};
module.exports = {dorequest}
In the route I've done this:
var getit = require ('./getit.js');
/* GET users listing. */
router.get('/', function(req, res, next) {
var ret = getit.dorequest();
res.send(ret);
console.log('res out' + ret);
});
What I get in the console is
res out[object Promise]
and the response is of course empty.
What am I doing wrong? I've been playing with this for a week now, tried various methods, but I keep getting similar results. I'm obviously missing something out, and would appreciate some help.
Thanks!
Object is empty because it was written on the console before the Promise is resolved. You have to wait until Promise is resolved and then send the response back so try to change your code like this:
var getit = require ('./getit.js');
/* GET users listing. */
router.get('/', function(req, res, next) {
getit.dorequest().then(function(data) {
console.log('res out' + data);
res.send(data);
});
});
Since you are using async/await approach all you need to do is to place await before getit.dorequest();
so this line will look like var ret = await getit.dorequest();

how to publish a page using node.js

I have just begun to learn node.js. Over the last two days, I've been working on a project that accepts userinput and publishes a ICS file. I have all of that working. Now consider when I have to show this data. I get a router.get to see if I am at the /cal page and..
router.get('/cal', function(req, res, next)
{
var db = req.db;
var ical = new icalendar.iCalendar();
db.find({
evauthor: 'mykey'
}, function(err, docs) {
docs.forEach(function(obj) {
var event2 = ical.addComponent('VEVENT');
event2.setSummary(obj.evics.evtitle);
event2.setDate(new Date(obj.evics.evdatestart), new Date(obj.evics.evdateend));
event2.setLocation(obj.evics.evlocation)
//console.log(ical.toString());
});
});
res.send(ical.toString());
// res.render('index', {
// title: 'Cal View'
// })
})
So when /cal is requested, it loops through my db and creates an ICS calendar ical. If I do console.log(ical.toString) within the loop, it gives me a properly formatted calendar following the protocol.
However, I'd like to END the response with this. At the end I do a res.send just to see what gets published on the page. This is what gets published
BEGIN:VCALENDAR VERSION:2.0
PRODID:calendar//EN
END:VCALENDAR
Now the reason is pretty obvious. Its the nature of node.js. The response gets sent to the browser before the callback function finishes adding each individual VEVENT to the calendar object.
I have two related questions:
1) Whats the proper way to "wait" till the callback is done.
2) How
do I use res to send out a .ics dynamic link with
ical.toString() as the content. Do I need to create a new view for
this ?
edit: I guess for number 2 I'd have to set the HTTP headers like so
//set correct content-type-header
header('Content-type: text/calendar; charset=utf-8');
header('Content-Disposition: inline; filename=calendar.ics');
but how do I do this when using views.
Simply send the response, once you got the neccessary data! You are not required to end or send directly in your route but can do it in a nested callback as well:
router.get('/cal', function(req, res, next) {
var db = req.db;
var ical = new icalendar.iCalendar();
db.find({
evauthor: 'mykey'
}, function(err, docs) {
docs.forEach(function(obj) {
var event2 = ical.addComponent('VEVENT');
event2.setSummary(obj.evics.evtitle);
event2.setDate(new Date(obj.evics.evdatestart), new Date(obj.evics.evdateend));
event2.setLocation(obj.evics.evlocation)
});
res.type('ics');
res.send(ical.toString());
});
});
I also included sending the proper Content-Type by using res.type.
Also: Don't forget to add proper error handling. You can for example use res.sendStatus(500) if an error occured while retrieving the documents.

Resources