<a hrerf=""> for download files with express and Node.JS - node.js

With Apache this this really easy, but with Node.JS I don't think so. Simply, I want that when a user click something like this: <a href="/dir/file.png">, he starts to download the file. When I do that, I'm redirected to http://foo.com/fir/file.png, and I visualize the photo. Also say that I have in the app configure this app.use(express.static(__dirname + '/public'));, so, the file is in the public path, and the public path is declared as static. And, when the users click, I dont want that he will be redirected and then the download starts.
I know this is posible, it's just click a link and a download starts! But I don't know how to do it.
Thank's advance!
EDITED:
The HTML where is the <a href="">for the download is here:
app.get('/:user/:id', function (req, res){
usermodel.findOne({ user: req.params.user }, function (err, user){
var imagen = user.imagen.id(req.params.id);
if (err) throw err;
res.render('photo.ejs', {
user: user,
photo: imagen,
});
});
});
Is necessary to create a new app.get? If I do that, I would get redirected? I'm trying to do this without getting redirected.

This depends on the headers you're sending with the image.
To make the browser download the image instead of displaying it, you need to set a "Content-Disposition: attachment" header.
Since you're using the static middleware, this is a bit trickier to do than in your own request handler function. You'll have to inject a middleware before the static one.
app.use(function(req, res, next) {
if (req.path.split('/')[0] === "downloads")
res.attachment(); //short for res.set('Content-Disposition', 'attachment')
next();
});
app.use(express.static(__dirname + '/public'));

Similarly to #rdrey's answer, make the browser download a file if there's ?dl query parameter in the url.
app.use('/gifs/*.gif', function(req, res, next) {
if (req.query.dl !== undefined) res.attachment();
next();
});
app.use('/gifs', express.static(__dirname + '/gifs'));

Related

How can i refresh the current page using node js and express

I want to refresh my page using respone and here is my code:
app.post("/delete",function(req,res){
res. <<-HERE I WANT TO REFRESH THE CURRENT PAGE USING "res."
})
If you think this question is stupid, please forgive me for that because iam a beginner :)
You can either redirect the browser to the page URL after the delete action:
app.get("/", function(req, res) {
res.render("page.ejs");
});
app.post("/delete", function(req, res) {
/* Carry out deletion */
res.redirect("/");
});
or you can include the code that generates the page in both the GET and POST routes:
app.get("/", function(req, res) {
res.render("page.ejs");
});
app.post("/delete", function(req, res) {
/* Carry out deletion */
res.render("page.ejs");
});
The important point is that, in both cases, the rendering of the page must take into account the prior deletion. Without you sharing more of your code, we cannot judge whether that works in your case.

expressjs middleware firing twice

I am trying to restrict all pages if the user is not authenticated.
The strange thing is that my middleware is being called twice when I call the login page.
THe following are my code
app.use((req, res, next) => {
if (req.session.user) {
res.session.user = req.session.user;
}
if (req.isAuthenticated() || req.path === '/' || req.path === '/login'){
console.log('inside next');
next()
}else{
console.log('inside redirect');
res.redirect('/')
}
});
app.get('/', (req, res) => {
console.log('inside /')
res.render('./login', {
css: ['login.css'],
js: ['login.js']
})
});
When I go to localhost:8000/ which is my root page, it prints out following in the console
inside next
inside /
inside redirect
inside next
inside /
As you can see after get('/') is called, the middleware is called once again to redirect the page. Why is this? If I remove the middleware, / gets called only once.
I found out why...
Apparently Chrome recently added a support for source map ESRI : Failed to parse source map
since the source map was not included in my vendor folder, it could not find the source map and refreshed the page.
So from now gotta take caution when copying bootstrap files - copy the source maps with the css file so that it doesn't refresh twice

can I create a route that could be use both for serving HTML and REST API?

Okay here's the scenario, to my knowledge there are three ways to create a web application
Traditional way: Render the HTML page from the server
Not sure: Create an API and let the user's browser to download the
Javascript application (Angular, React, Ember) to get a highly
interactive application
The future: Isomorphic web app, which render the HTML together with the client-side technologies (Angular, React, Ember) from the server.
I'm planning to use the third way, due to faster load page, but the problem right now is if I were about to create a mobile application.
My stack: Node.js + React
Let say if I'm planning to go mobile, do i need to duplicate the same route and logic ?
Current problem
app.get('/users', function(req, res) {
res.render('index', { message: "Hey Im Jack" });
});
app.get('/api/users', function(req, res) {
res.json({ message: "Hey Im Jack" })
});
Is there any way that I could use to for one route to serve both the HTML and REST?
You can ultimately only send either HTML or JSON (in case of REST).
The /api/xxx route syntax makes it clearer which path serves the JSON.
But you can depend on client's request header to check whether they requested JSON or HTML
app.get('/users', function(req, res) {
if (req.headers.accept && req.headers.accept.match(/json/))
res.json(data);
else
res.render('index', data);
});
Angular's $http usually requests json by default, not sure about others, but you can set the headers. Browsers normally request text/html, but I'm not sure.
Or if you're only concerned about not having to repeat the logic that fetches the data, you could put a middleware preceeding both:
// regex to match both routes
app.get(/.*users/, function(req, res) {
res.locals.data = { message: "Hey Im Jack" };
req.next();
});
app.get('/users', function(req, res) {
res.render('index', res.locals.data);
});
app.get('/api/users', function(req, res) {
res.json(res.locals.data)
});

Using Express 4 how to redirect to my own route without losing req and response data?

I have my application structured with 3 Routes (api, admin, default). Each lives in there own file and has it's own middleware and exports a Route. The problem I am facing is when I want to forward to another route that lives on a different router. Essentially I want to call the same function so that I am not serving up the same view from multiple locations.
I don't want to user res.redirect('/someplace') because I want to be able to pass the req and res objects on to the method.
|-app.js
|-routes
|---admin.js
|---api.js
|---default.js
The routes are required and used in app.js as follows
app.use('/api', require('./routes/api')(passport);
app.use('/admin', require('./routes/admin')(passport);
app.use('/', require('./routes/default')(passport);
Inside of admin if have a situation where I need redirect to login and pass some data
// authenticates all routes for the admin router
router.use(function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.flashMessage.push('Session expired'); //is lost after redirect
res.redirect('/login');
//do I need to restructure my whole app so that I don't
//have to call res.redirect('login')
});
Any ideas on how to structure this? Do I need to export every method and keep all of my routes in one router file? That doesn't very clean, but if the functions are somewhere else it may be too messy.
You can forward it by calling the next callback ,but only if you do not use any paths.
app.use(function(req, res, next) {
// ... api
next();
});
app.use(function(req, res, next) {
// ... admin
next();
});
Another option is use * that will match all paths:
app.use("*", function(req, res, next) {
var path = req.path; // just example how it can be done
if (path === "/api") {
// ...
path = "/admin";
}
if (path === "/admin") {
// ...
}
});
Edit:
I don't think that express has something like next('/login'); ,so basically function that can forward a request to another path and I don't think that is right to have something like this. If a client ask for /admin you should send this particular page and not the page that is under /login. If you want to send back to a client the login page than just redirect it as you did it in your question. I understand that you want to keep the req, res ,but then is the problem in the proposal/structure of your webapp.

Unable to serve image (png) with node.js and express

I've studied similar questions on SO but haven't found a solution to my problem... I've set up an express route to serve images but I can't get it to return an image from where it's stored. Notice I've included a statement to allow requests from any origin. What happens is that when I make a request to http://localhost:8080/images/x10.png the response I get is an empty image element with src="http://localhost:8080/images/x10.png instead of from http://ubuntubox.dev/images/x10.png, which is where the image is actually located and is the path I'm ultimately passing to the request method. What am I missing? Thanks.
app.get('/images/*', function(req, res, path){
var imagePath = req.url,
url = 'http://ubuntubox.dev' + imagePath;
request(url, function(error, response, img) {
if(!error && response.statusCode === 200) {
res.header('Access-Control-Allow-Origin', '*');
res.writeHead(200, {'Content-Type': 'image/png' });
res.end(img, 'binary');
} else if(response.statusCode === 404) {
res.status(404);
res.type('txt').send('oops');
}
});
}).listen(8080, '127.0.0.1');
I don't know if you still have this problem, but..
The solution for your problem is just putting a .pipe(res) and it will send the file to the response
app.get('/images/*', function(req, res, path){
var imagePath = req.url,
url = 'http://ubuntubox.dev' + imagePath;
request(url).pipe(res);
}).listen(8080, '127.0.0.1');
If you want to serve images and other assets in a way that makes sense and doesn't require you to write a million routes, try this:
Create a new folder "public" and move all of your assets into it.
Open server.js and add the following line:
app.use(express.static('public'))
Your assets should now be available like so:
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html
Soure: https://expressjs.com/en/starter/static-files.html
Just figured this out for myself in express 4
app.get('/images/img1.png', function(req, res){
res.sendFile('/Absolute/path/to/the/file/images/img1.png');
});
user2879041 has already answered what he found useful, still I would think of another way for serving images, (where I shall not write a route for each file manually and the send the file to the browser).
As you are already using express, just server tyhe static images directly, you have already got that in express.static
app.use(express.static('/Absolute/path/to/the/file/images/img1.png'));
benefit of using express.static is that you would just keep adding the images inside the folder you want to be static and express will serve the images for you(no need to add any code).
I am not sure if it's the same case or not.
But here is my answer:
var path = require('path');
var express = require('express');
var app = express();
var dir = path.join(__dirname, 'public');
app.use('/public', express.static(dir));
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
Notice this line:
app.use('/public', express.static(dir));
You need to add the path again with the app.use method
I don't get the idea of adding this part, but it was the only way to make it works.
and without it keeps responding 'Error' and I can not access this file.
hopefully, I could help you.

Resources