Changing the header of the response on NodeJS using request - node.js

I have the following problem:
I want to get a static file from another server, and give it back to the user with another content-type header.
The following code works just fine, but I can't figure out a way to change the response header, though.
const request = require('request');
app.get('video', function (req, res) {
request.get('http://anotherurl.com/video-sample.mp4').pipe(res);
});
I tried to do this thing more manually, but the response was very slow.
app.get('video', function (req, res) {
request.get('http://anotherurl.com/video-sample.mp4', function(error, response, body) {
// ...
res.setHeader('content-type', 'image/png');
res.send(new Buffer(body));
});
});
Can you guys help me with that?
Thanks

Just set the response header when the 'response' event fires.
app.get('video', (req, res) => {
request.get('http://anotherurl.com/video-sample.mp4')
.on('response', response => {
res.setHeader('Content-Type', 'image/png');
// pipe response to res
// since response is an http.IncomingMessage
response.pipe(res);
});
});

Related

Conditional redirect with express / request-promise

I am rather new with express together with the request-promise module,
and need to create a service S
that is called from serverA
and after S has asked ServerB for some additional info,
it redirects the request of serverA to ServerC.
Since I get a
Error: Can't set headers after they are sent.
even though I do not add something by myself, I wonder someone could help me to get this workflow straight.
This is the code:
`
const express = require('express')
const rp = require('request-promise')
...
app.get('/dispatch', cors(), (req, res, next) => {
var options = {
uri: 'https://ServerB/calc-something..',
headers: {
'User-Agent': 'its-me',
'Data': data_from_serverA
},
resolveWithFullResponse: true, // Get statuscode
json: true // Parse the JSON string in the response
};
rp(options) // Do request to serverB
.then(function (response) {
console.log(`ServerB responded with statuscode ${response.statusCode}`)
// No error, so redirect original res
res.redirect('https://serverC/...') // error occurs here
return next(response)
})
.catch(function (err) {
console.log(`ServerB responded with error ${err}`)
return next(err) // send 500 to serverA
})
})
`
Your cors() middleware is setting CORS headers. This is causing the headers to be sent while your promise is resolving.
A redirect ALSO sends headers, and this is the issue. A redirect sets a location header, but you've already sent the headers so that won't work.
The solution is to split your final middleware into two. First, check to see if a redirect is needed and if so, do that. Otherwise, set whatever data you need on the req object and handle this AFTER the cors call.
Your final route will look something like:
app.get('/dispatch', checkRedirect, cors(), (req, res, next) => {
//do something useful, or send your error
})
The contents of your checkRedirect function will be pretty similar to what you have above. However, you do not pass data to the next() function. That just passes control to the next middleware. Instead, put any data you need on the req object and handle it in the final middleware, AFTER cors. If all you are doing is setting a 500 error, you don't even need CORS for that.
According to #Rampant 's answer,
this is how I did it with request-promise (rp):
function checkPrecondition(req, res, next){
req.precondition = false
rp({ method: 'POST',
...
})
.then((data) => {
...
req.precondition = true
next()
})
.catch((data) => {
...
next()
})
}
and in the express handler:
app.post('/query', checkPrecondition, cors(), (req, res, next) => {
if(!req.precondition){
res.status(400).send(JSON.stringify({status: 'insufficient'}))
return
}
res.redirect('target.host')
})
Thanks for clearifying the CORS issue.

Why is my Express server response truncating during SSR only?

I am using Next.js, Redux, and Express. My page has this code:
static async getInitialProps({store, isServer, pathname, query}) {
const res = await fetch('http://localhost:3001/tutorials');
const tutorials = await res.json();
store.dispatch(tutorialsReceived({tutorials}));
}
I get the React debug error saying my server response is different than my client. It's expecting a very long JSON response (252KB), and the server render is getting cut off incredibly early. I have tried two ways to send the file and am unsure why either would cut short.
// Try 1
server.get('/tutorials', (req, res) => {
fs.createReadStream('./common/content.json').pipe(res);
});
// Try 2
server.get('/tutorials', (req, res) => {
fs.readFile('./common/content.json', 'utf8', function(err, tutorials) {
res.send(tutorials);
});
});
Modifying the file to be smaller like {a:1,b:2,c:3} results in no error for my sanity check.
Looks like express is setting wrong Content-Length header in the response due to which your JSON gets chopped off. You can set it explicitly and that should work.
server.get('/tutorials', (req, res) => {
fs.readFile('./common/content.json', 'utf8', function (err, tutorials){
res.writeHead(200, {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(tutorials, 'utf8')
})
res.send(tutorials);
});
});

modify response in express/nodejs

i am making multiple streamdata in Nodejs using express.
this is how i make a url:
app.get('/temp/1', function(req, res){
res.send('hello, i am not modified')
})
my question is: is it possible to modify the response of that url?
i tried like this:
app.get(/modify/1, function(req, res){
app.get('/temp/1', function(req, res){
res.send('hello, i am modified')
})
res.send('done');
}
So i would think that the response is changed, but nothing happens actually.
is there a way to achieve it?
Here's an example using express-modify-response:
const modifyResponse = require('express-modify-response');
...
let modify = modifyResponse(
function(req, res) { return true }, // always modify the response
function(req, res, body) { return 'hello, i am modified' } // the new response
);
app.get('/temp/1', modify, function(req, res){
res.send('hello, i am not modified')
})
EDIT: second attempt. You have an endpoint /temp/1 that sends a particular response, and you want an endpoint /modify/1 that will take that response and modify it.
This calls for some abstraction:
function someFunction(id) {
return 'hello, i am not modified';
}
app.get('/temp/1', function(req, res) {
res.send(someFunction(1));
});
app.get('/modify/1', function(req, res) {
let value = someFunction(1);
// Remove the word `not`.
value = value.replace(/not /, '');
res.send(value);
});
So both handlers use the same function, that provides the actual output, but /modify/1 modifies the output before returning it to the client.

node http-proxy: async modification of request body

I need to modify the request body asynchronously. Something along the lines of this:
proxy.on('proxyReq', function(proxyReq, req, res, options) {
if(req.body) {
new Promise(function(resolve){
setTimeout(function() { // wait for the db to return
'use strict';
req.body.text += 'test';
let bodyData = JSON.stringify(req.body);
proxyReq.setHeader('Content-Type','application/json');
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
// stream the content
proxyReq.write(bodyData);
resolve();
},1);
});
}
});
When I run this I get the error saying cannot modfiy headers once they have been set. Which makes sense.
How can I halt the sending of the request until I'm ready? I've looked at removing various listeners from proxyReq without success..
By looking at the source code #-) it seems like it's not really possible because the proxyReq event is sent and then the code moves on.
If it would instead wait for a promise, it would be possible (if you'd return that promise as well).
A minimal fork on this lib could be for example:
// Enable developers to modify the proxyReq before headers are sent
proxyReq.on('socket', function(socket) {
if(server) { server.emit('proxyReq', proxyReq, req, res, options); }
});
(proxyReq.proxyWait || Promise.resolve())
.then( ... // rest of the code inside the callback
And then
proxy.on('proxyReq', function(proxyReq, req, res, options) {
if(req.body) {
proxyReq.proxyWait = new Promise(function(resolve){
setTimeout(function() { ...
But depending on your use case, there might be other solutions as well. For example, consider if it's really necessary that you use this proxy library. It You could alternatively use http directly, where you have all the control on the events and callbacks.
You can set selfHandleResponse: true inside the HttpProxy.createProxyServer. This then allows (and forces) you to handle the proxyRes manually!
const proxy = HttpProxy.createProxyServer({selfHandleResponse: true});
proxy.on('proxyRes', async (proxyReq, req, res, options) => {
if (proxyReq.statusCode === 404) {
req.logger.debug('Proxy Request Returned 404');
const something = await doSomething(proxyReq);
return res.json(something);
}
return x;// return original proxy response
});
I came here looking for the solution to a slightly different problem: Modifying the request headers (not body) before proxying.
I post this here in case that it is helpful to others. And maybe the code can be adapted to also modify the request body.
const http = require('http');
const httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({});
var server = http.createServer(function(req, res) {
console.log(`${req.url} - sleeping 1s...`);
setTimeout(() => {
console.log(`${req.url} - processing request`);
req.headers['x-example-req-async'] = '456';
proxy.web(req, res, {
target: 'http://127.0.0.1:80'
});
}, 1000);
});
server.listen(5050);

NodeJs: Sending picture with Express (Multer)

I have this code
app.get('/imgs/:id', function(req, res) {
// Validate that req.params.id is 16 bytes hex string
// Get the stored image type for this image
var stream = fs.createReadStream(path.join(UPLOAD_PATH, req.params.id));
stream.on("readable", function() {
res.setHeader('Content-Type', "image/jpeg")
stream.pipe(res)
})
stream.on('error', (e) => {
res.redirect(404, "404")
})
});
Now the problem is that I always get an error of
Error: Can't set headers after they are sent.
because I used the res.setHeader function.
However, i don't know how to solve it. Let's say I want to use in a page, that has obviously the res.send() function has well,
the <img src="imgs/pic">, then I must set the header for the this page request to "image/jpeg" because otherwise the browser wouldn't know it's an image and won't show it as one.
What can I do then?
Check Express response document here. Try this code
app.get('/imgs/:id', function (req, res) {
res.sendFile(req.params.id, {root: UPLOAD_PATH, headers: {'Content-Type': 'image/jpeg'}}, function (err) {
if(err) throw err;
else console.log('sent')
})
})

Resources