I need to be able to have multiple static (public) folders which I can achieve using the following:
app.use(express.static(path.join(__dirname, '/routes/mymod1/public')));
app.use(express.static(path.join(__dirname, '/routes/mymod2/public')));
This merges the 2 folders so they appear as one, but the problem with this is if I have the same filename in both folders, then the last file will win.
What I would like to do instead, is to dynamically route the static requests based on the requested route.
For example a static request to /mymod1/test.html would be directed to /mymod1/public/test.html and requests to mymod2/test.html would be directed to /mymod2/public/test.html
Is this possible ??
When you use the express.static middleware it try to resolve the file (in mymod1) and send it back. If no file is found the next middleware is call and try to resolve in mymod2 so the only the first one should win.
If you want to add a route, you can precise it as first argument:
app.use('/mymod1', express.static('...'))
Related
I'm trying to serve static file uploaded using ExpressJS and NodeJS with Typescript but getting 404 error.
the file I want to read is ./src/data/uploads/test.txt and I'm trying to access it from web browser directly.
Note: When I do it in Javascript it worked but not in Typscript.
index.ts file (app entry point)
import express from 'express';
import bodyParser from 'body-parser';
import helmet from 'helmet';
import {cdg, config} from './utils';
import {Mongoose} from './db/monogdb';
import { setRoutes } from './routes/route.decorators';
import cors from 'cors';
import './routes';
const app = express();
app.use(helmet());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use('/ftp', express.static('data/uploads'));
setRoutes(app);
app.listen(config.server.port, () => {
cdg.konsole("Server connected! :: " + config.server.port + "!");
});
Is there a specific way to serve static file with Typescript ?
Here's how express.static() works. You are apparently missing one of these steps, but your question is short of the details to identify exactly which step is not correct.
First, you define an express.static() middleware that contains some parameters. In your case, you've defined this:
app.use('/ftp', express.static('data/uploads'));
There are four elements that determine how this works:
The /ftp that must be at the start of any URL for this middleware to match.
The incoming URL request and how it was formed by the browser based on how you specified it in your HTML.
The current working directory that is combined with data/uploads to make a full path reference or you could build your own absolute path and not depend upon the cwd.
The files in cwd + /data/uploads that express.static() will attempt to match to the path of the incoming URL.
Let's look into these further:
Your middleware will first only look at URLs that start with /ftp. And, then for any URL it sees that does start with /ftp, it should take the rest of the URL and append it to data/uploads and see it finds a matching file in your local file system. It will use the current working directory in your server process at the time of the request to try to resolve the relative path data/uploads. That current working directory (if you haven't programmatically changed it) will depend upon how your app was started.
So, if you started your app with node index.js, then the current working directory will be the directory where index.js is located and express static will be looking in the data/uploads sub-directory below where 'index.js` is.
Then, we need to look at how the HTML tag that specifies this static resource is specified.
Let's say this is an <img> tag for example. If you specify something like this:
<img src="/ftp/hello.jpg">
Then, the browser will create a request to your server for /ftp/hello.jpg. Since that does start with /ftp, your express.static() middleware will take the rest of the path /hello.jpg and append that to data/uploads and build a path that looks like this:
path.join(process.cwd(), 'data/uploads', '/hello.jpg')
And, it will look for that resulting file in your local file system. If it finds that file, then it will serve that file and return it as the response. If it doesn't find that exact file, then it will call next() and continue routing to your other route handlers.
There are a number of common mistakes (things that can go wrong):
You don't specify the correct URL in your web page that lines up with your express.static() middleware line (including the /ftp prefix that your middleware specifies).
Your middleware isn't quite pointing at the right directory in your file system so it never finds anything.
You are using relative URLs in your web page which the browser combines with the path of your web page causing it to request something different than you want. Static resource URLs in your web page should nearly always start with / so they are not dependent upon the path of the parent page.
The files aren't quite properly located in the file hierarchy you are pointing to with your middleware (often off by one level).
One other thing I will mention. Since you're using TypeScript, that means you have to compile/build your script into a regular .js script before it can be run. This will typically be in a different directory location.
This different directory location creates opportunities for you to not be referencing the proper directory where your static resources are, since they are probably located relative to your TypeScript files, not the built Javascript files that you're running (that depends upon your build script).
Again, if you show us where everything is in your file system (TypeScript files, built JS files, static resources) and what the HTML tag that references the static resource looks like, we can help you debug that more specifically.
In my case I solved my problem like this: in the parameter relative to the directory path I used path.resolve and in its first parameter I used __dirname as the first parameter and the relative path of the target directory as the second one.
app.get('/', express.static(path.resolve(__dirname, '../static/'))); –
I have template settings that vary depending on the subdomain I’m using. Therefore I’m trying to find a way to set the express.static dynamically based on the subdomain name I’m using.
When app.use runs, template is undefined. If I run app.use inside app.get it is out of scope. And if I try to run app.use from a function it is also out of scope.
"template" is a variable that I get in app.get it is my subdomain and http request
app.use('/subdomain/:domain/bower',express.static(path.join(__dirname, '/public/' + **template** + '/bower')));
app.get('/subdomain/:domain',function(req,res,next) {
get('/stores/template/' + req.params.domain)
.then(function(body){
console.log("template: " + body.toString());
template = body;
res.render('store',{store:req.params.domain});
});
});
I’m pretty sure it has to do with scopes, but so far I haven’t been able to solve it. Any help would be appreciated
Your first app.use() and the express.static() call in it runs when your sever is first starting up. At that point, the template variable does not yet have a value. You can't really do things the way you're trying to do it.
app.get() runs immediately also, but its callback is not called until sometime in the future when an http request matching that route actually arrives. By then, when the template variable gets assigned, it's way too late for it to be useful in your prior app.use() statement.
This would be much easier if your server could just know which sub-domain it was serving when it was originally set up from a configuration file or something like that. If you intend for the same server to serve many sub-domains at once and you want it to serve different files based on the subdomain, then you will have to code completely differently because you can't just use plain route matching like express.static() does since what you really want is sub-domain + route matching which isn't a built-in feature that I'm aware of.
I think if I was trying to solve this, I'd have my first middleware examine the sub-domain of the request and insert it into the front of the URL making a unique pseudo-URL for each sub-domain. Then, you could do normal routing on that pseudo-URL which is what the rest of the middleware and routes will see as the request URL.
I'm having a major issue with Routing in Express.
In my project, there is a folder /public.
Inside /folder I have some other folders like
- public
|- user
|- common
Initially, the only way pages were served by my Node.js server was through res.sendFile(../..). The problem was that the .js files and .css files did not know where to go.
So I added
app.use('/', express.static(__dirname + '/public'));
But now the problem is, if I try to visit /user what happens is, that the static version of the index.html file in that folder is returned, and my route defined in the node app is ignored!
This route - and most importantly the auth middleware is never touched!
How do I reconcile the need to serve files from a static folder, but also may have routes of the same name that I want to control more closely?
app.use('/user', userauth, userRoutes);
Assuming /user is some sort of API I don't think express.static was intended to be used that way. I think the best solution would be to use different routes. You could add something like /api/ to the beginning of all your routes or make sure your static files are organized under /css, /js, /partials, etc.
If you absolutely must support /user for static files AND your api calls you will need to ditch express.static and use something like the Accept header with custom middleware that determines what the browser is asking for. Depending on the scenario this may get complicated to support all the variables. A simple example would be something like this:
app.use(function(req, res, next){
// check Accept header to make sure its a JSON request
if(req.accepts('application/json') && !req.accepts('html')) {
// JSON request so forward request on to the next middleware(eventually hitting the route)
return next();
}
// NOT a JSON request so lets serve up the file if it exists...
// TODO use req.path to check if file exists - if not 404 - will also need to map paths
// to /users to check for /users/index.html if you need to support that
var fileExists = false;
return fileExists ? res.sendFile('...') || res.status(404).send('Not Found');
});
You would have to make sure when the client calls /users it sets the Accept header to application/json. Most client side frameworks have a way to do this for all AJAX requests.
I'm using Express and have my static files at a specific path and serve them trought static() middleware like that:
app.use(express.static(__dirname + '/public'));
I also use bower and used to configure a .bowerrc file to install stuff in that static used path.
I was wondering if I could not redefine a second static middleware like that:
app.use('/bower', express.static('/bower_components'));
So I get rid of my .bowerrc file.
But it's not working, is this sort of thing possible or am I completely misleading?
Yes, you absolutely can do that. If the first argument to use is a string, you're mounting the middleware to a specific URL path.
It's probably not working because you're specifying an absolute path for the static middleware – did you really mean bower_components under the root directory /?
I'm trying to build a webapp where:
http://mydomain.com/static/x.png serves x.png as a static file using Connect's static middleware
http://mydomain.com/other_stuff does other stuff
My directory structure is
start_server.coffee
static/
x.png
In start_server.coffee I have:
app = connect()
app.use connect.staticCache()
app.use connect.static(__dirname + '/static')
app.use ...middleware that serves the dynamic parts of my app...
app.listen 80
When I try http://mydomain.com/static/x.png, the request bypasses the static server and gets routed to the rest of my app. I stepped through the code in a debugger and it looks like static is trying to lookup static/static/x.png instead of static/x.png.
I was able to get it working by changing connect.static(_dirname + '/static') to connect.static(_dirname), but now it will serve stuff that's not in the static directory which is not good!
What's the cleanest way of doing what I'm trying to do? I could probably use Express's routing functionality, but I don't particularly want to use Express unless I have to, since the rest of my app handles routing its own way.
Thanks!
So the issue is the mismatch between your URL paths and your filesystem layout. There are 2 easy-peasy get-on-with-your-life solutions.
Remove "static/" from your URLs. The static middleware will only serve files under the static directory but the URLs won't include the word "static".
Do this: mkdir public && mv static public. Leave the public directory empty other than the static subdirectory. Now your URLs can stay the same and in your code you need app.use connect.static(__dirname + '/public').
Now this is what the static middleware provides out of the box. The URLs have to map simply to the filesystem. This is why it "just works" and is simple.
If you really want to have static/ in your URL but not map to a directory underneath your static root, add a middleware before the static middleware that alters req.path to remove the leading "/static", then call next() and I think that will trick the static middleware into doing what you want.