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')
})
})
Related
I'm trying to download a photo through a URL passed as a query string using Express, but every time I try to use it, I get Error: Invalid URI "favicon.ico" Is there a way I can get my browser to stop requesting a favicon? For downloading images, I'm using the image-downloader package (NPM page)
Code:
app.get('/:url', (req, res) => {
let url = req.params.url;
const options = {
url: url,
dest: /path'
};
download.image(options)
.then(({ filename, image }) => {
console.log('File saved to ', filename);
})
.catch((err) => {
console.log(err);
});
res.send("Done");
});
It's probably easiest to just make a route for favicon.ico in your server.
app.get('/favico.ico', (req, res) => {
res.sendStatus(404);
});
Of course, you could actually send a valid icon too if you wanted, but this will at least keep your Express server from showing an error.
FYI, this has nothing to do with the image-downloader. This has to do with the browser requesting a favico.ico icon that it uses to show in the URL bar (and some other places in the browser UI). If your server returns a 404 for favicon.ico, the browser will use a generic icon in its UI.
If you want to make yourself a simple favico.ico, you can go here and it will help you generate one and then you can change the above route to:
app.get('/favico.ico', (req, res) => {
res.sendFile("myfavico.ico");
});
Try using another package like request module. I believe it got this type of things handled.
var fs = require('fs'),
request = require('request');
var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
download('https://www.google.com/images/srpr/logo3w.png', 'google.png', function(){
console.log('done');
});
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);
});
});
I have an express/node app which exposes a GET end point via express router something like /api/user. The response is a JSON and i want to download the JSON to a file when i hit localhost:8080/api/user.
I tried with res.download but not sure how to handle the response data with it. This could be a duplicate question but i cannot find an example especially for this use case.
When the end point is invoked in browser it should prompt for download and then should get downloaded to the default location.
router.route('/user')
.get((req, res) => {
MyService.get().then((result) => { // the get method resolves a promise with the data
// Prompt for download
}).catch((err) => {
console.log(err);
res.status(500).json({
status: 500,
data: err
});
});
});
So i was able to do this in one of the 2 ways below,
router.route('/user')
.get((req, res) => {
MyService.get().then((result) => {
res.attachment('users.csv');
/*or you can use
res.setHeader('Content-disposition', 'attachment; filename=users.csv');
res.set('Content-Type', 'text/csv');*/
res.status(200).send(result);
}).catch((err) => {
console.log(err);
res.status(500).json({
status: 500,
data: err
});
});
});
If I understand correctly, you want to save the sent data of /api/user to a file that you are sending in a route?
var fs = require('fs')
app.get("/api/user", function(req, res){
var data = fromDb()
fs.writeFileSync("/tmp/test", JSON.stringify(data))
res.send(data)
})
You need to write the JSON response to a file using the node filesystem module. You can check out an example here Writing files in Node.js
If I got you right then You can try Content-Type and Content-disposition headers like below:
res.writeHead(200, {'Content-Type': 'application/force-download','Content-disposition':attachment; filename={your_file_name}.json});
res.end(data);
NOTE :
data in res.end(data) is your json data.
{your_file_name}.json is your actual file name , give it any name.
When I hit my api I want to redirect my url from https://myapp.herokuapp.com/token/aaa.bbb.ccc to https://myapp.herokuapp.com/messages/:id. I also want to render my message view
Code:
app.get('/token/:id' , (req, res) => {
var decoded = jwt.verify(req.params.id, 'blabla');
Message.findById(decoded.messageId, (err, message) => {
if (err) res.json({error: err})
res.render('message', {message})
})
})
Here, I successfully render my message view but the URL for the below api is still https://myapp.herokuapp.com/token/aaa.bbb.ccc and not https://myapp.herokuapp.com/messages/:id
Another attempt:
app.get('/token/:id' , (req, res) => {
var decoded = jwt.verify(req.params.id, 'blabla');
Message.findById(decoded.messageId, (err, message) => {
if (err) res.json({error: err})
res.redirect('/messages/'+message._id)
})
})
Now, the URL is https://myapp.herokuapp.com/messages/:id but the message view is not rendered. A JSON is rendered that displays the message
How do I redirect to https://myapp.herokuapp.com/messages/:id and also render the message view?
You should first redirect:
app.get('/token/:id' , (req, res) => {
var decoded = jwt.verify(req.params.id, 'blabla');
Message.findById(decoded.messageId, (err, message) => {
if (err) return res.json({error: err}); // see #partycoder's answer
res.redirect('/messages/'+message._id)
})
})
Next, you need to adjust the route handler for /messages/:id. Right now, it sounds like it's only used for XHR requests, so it will always return JSON. You can add a check to see if the request is an XHR-request or not, and either return JSON (for XHR) or a rendered template (for non-XHR):
app.get('/messages/:id', (req, res) => {
...
if (req.xhr) {
return res.json(...);
} else {
return res.render(...);
}
});
(documentation for req.xhr, be aware that the method on which this is based is not foolproof)
However, perhaps it's better to use content negotiation, where the client explicitly tells your server what format the response should be. The upside of this is that it's much more explicit, the downside is that you may have to change some client-side code. Documentation here: http://expressjs.com/en/4x/api.html#res.format
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);
});
});