Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serve static content (images, fonts etc.) using iron router

I just started working with iron router on meteor. I need to show an image on homepage. I was able to configure route for 'home' using the client side routing. For static files I tried to google and found that adding a server side route might help. So, I added the following code on server's router.js.

Router.map(function() {
    this.route('files', {
        path: '/files/:path(*)',
        action: function() {
            var path = this.params.path;

            console.log('will serve static content @ '+path);
            this.response.sendfile(path);
        }
    });
});

When I try to access http://localhost:3000/files/someImage.png, it says that no route is defined for /files/someImage.png. Am I doing something wrong? Is there any other way to serve static files using iron router?

like image 880
Goje87 Avatar asked Jan 24 '14 19:01

Goje87


3 Answers

Instead of doing all this, you can just put the files under your public directory. If you add the file:

myApp/public/images/kitten.png

You can access it from your templates like:

<img src="/images/kitten.png">

No routes are needed to make that work.

Beware of overlooking the lead slash.

<img src="images/kitten.png">

the above example will work from your top level routes like /books which makes it easy to miss, but fail on /books/pages.

like image 124
David Weldon Avatar answered Nov 18 '22 14:11

David Weldon


You probably just need to make sure that the route is in a common area visible on both client and server (This route actually runs on the server) and specify where: 'server'. In addition we need to load the actual file off of disk, which means we need the actual path on the server to the file, and we need to load the 'fs'.

var fs = Npm.require('fs');

Router.map(function() {
  this.route('files', {
    path: '/files/:path(*)',
    where: 'server',
    action: function() {
        var path = this.params.path;
        var basedir = '~/app/';

        console.log('will serve static content @ '+ path);

        var file = fs.readFileSync(basedir + path);

      var headers = {
        'Content-type': 'image/png',
        'Content-Disposition': "attachment; filename=" + path
      };

      this.response.writeHead(200, headers);
      return this.response.end(file);
    }
  });
});

A couple of notes: You should probably move the actual download code into a server only function and call that instead, passing the response in to the function.

You should also do some validation of the path so that you aren't allowing anyone to arbitrarily download files on your server.

In addition, this is setting the content type explicitly, which you will probably want to do for images, but maybe not for other content types. For a generic type you can set it to application/octet-stream

Of course as was mentioned, if your only goal is to have some static content available at deploy time, you should just use the /public directory.

like image 30
MrMowgli Avatar answered Nov 18 '22 16:11

MrMowgli


This is a bug in iron-router, which they say is fixed, but I'm still encountering the problem and others have reported on that github issue that it's still a problem.

Edit: It seems to work for files that are directly in /public, but not for files in folders within /public.

like image 4
foobarbecue Avatar answered Nov 18 '22 16:11

foobarbecue