Express wildcard rule - node.js

I am hosting a single page app with Node and Express. I use the static middleware for the client. I am using path URLs to navigate the app, for example domain.com/profile/134. I am using history.pushState to change pages internally on the client, and this works fine. What I am missing is a wildcard rule on the server to catch all possible paths when the user accesses my page directly to a path that is not root. If I try to access domain.com/profile/134 directly I get this: "Cannot GET /profile/134". I have tried to insert a wildcard get at the end of server.js, but it seems to be hit every time, also when I access the page root. This is my relevant code:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/../client'));
app.get('/*', function(req, res) {
console.log('wildcard');
});
Is this the correct GET wildcard rule to achieve what I need, and how can I serve the static client inside this handler? My client side will find the right page afterwards as long as the initial path is preserved. I basically want this wildcard rule to behave the same as the static rule, but keep the initial path.

You can use a hack
app.get('/:url', function(req, res) {
console.log('wildcard');
});
or try this one
app.get('/(.*)', function(req, res) {
console.log('wildcard');
});
[edited]: this should work as you expect:
var express = require('express');
var app = express();
app.get(/(.*)/, function(req, res) {
console.log("req.path", req.path);
res.send('success');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});

I ended up using an npm module named express-history-fallback-api to solve this. Out of the box it solved both simple and advanced paths, like domain.com/settings and domain.com/profile/username
https://www.npmjs.com/package/express-history-api-fallback

Related

ExpressJS Static not working

Been having some issues with express, I can't seem to serve static files.
If I do :
app.use('/*', express.static(DIST_FILEPATH));
it gives me a 301 or something, basically doesn't find the file (I have tried it in incognito mode also to avoid chasing/whatever issues).
But for some reason if I do:
app.use('/*', function (req, res, next) {
console.log(req.originalUrl);
console.log(DIST_FILEPATH);
res.sendFile(path.join(DIST_FILEPATH, req.originalUrl));
});
It works just fine and both paths are correct. Why is this happening and how can I solve it?
Express version: 4.14.1
Your issue is that you have the syntax slightly off. What you can do if you want to only server static files is use app.use(express.static(path.join(__dirname))); then when you go to http://localhost:3000/ you can add things like index.html so that you can see your html file. Here is an example of a simple express server that serves static files:
var express = require('express');
var path = require('path');
var app = express();
app.set('port', 3000);
app.use(express.static(path.join(__dirname))); //here you can change your path. for example you could add + 'public' if all of your files where in the 'public' directory
var server = app.listen(app.get('port'), function() {
var port = server.address().port;
});
You can run this with node <filename>.js then just go to http://localhost:3000/index.html or http://localhost:3000/myMusicFile.mp3 for example.
hope this helps!

Capture all http requests with node/express

I am looking to capture all of the data from any request (images, fonts, css, js, etc) on my website so that I can capture the file details, specifically the file name and file size. I have found almost an identical question/solution:
Node.js : How to do something on all HTTP requests in Express?
But the solution appears to be deprecated with Express v4. Is there a simple solution to do this? As another approach I have tried the below solution with no luck:
var express = require("express");
var path = require("path");
var port = process.env.PORT || 3000;
var app = express();
var publicPath = path.resolve(__dirname, "public");
app.use(express.static(publicPath));
app.get("/", function(req, res){
// I want to listen to all requests coming from index.html
res.send("index.html");
});
app.all("*", function(){
// can't get requests
})
app.listen(port, function(){
console.log(`server listening on port ${port}`);
});
Also I am not looking to do this from Fiddler/Charles because I am looking to display this data on my site.
Express routes are predicated on order. Notice the answer that you linked in your question has the middleware defined, and used before all other routes.
Secondly you're trying to implement something that requires middleware, not a wildcard route. The pattern in link you provided in your question is not deprecated according to their docs.
app.use(function (req, res, next) {
// do something with the request
req.foo = 'testing'
next(); // MUST call this or the routes will not be hit
});
app.get('/', function(req, res){
if (req.foo === 'testing') {
console.log('works');
}
res.send("index.html");
});

Setting up node-php to deliver php files to client using express?

Node-php is an npm package:
https://www.npmjs.com/package/node-php#nodephp---run-wordpress-and-other-php-scripts-with-node
My problem: Up until now I only needed static html files for my webpage, which were delivered okay.
However, now I want to deliver a php file as well. If i simply try to send it like a static file a popup to save the file appears instead of displaying it. So i set up node-php which claims to be able to deliver php files correctly as well. But, it's not working.
How the webpage looks with the below code, going to either the html page or the php page
Either help to make node-php work, or another method to fix this are appreciated.
var express = require('express');
var php = require("node-php"); //Required by node-php
var path = require("path"); //Required by node-php
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use("/", php.cgi("/usr/bin/php")); //Required by node-php
//LISTEN
app.set('port', process.env.OPENSHIFT_NODEJS_PORT || 8080);
app.set('ip', process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1');
http.listen(app.get('port'), app.get('ip'), function () {
console.log('LISTENING!');
});
app.use(express.static('public'));
//SEND FILES
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
app.get('/phpfile', function (req, res) {
res.sendFile(__dirname + '/phpfile.php');
});
The argument passed to php.cgi() is supposed to be your PHP root directory (where your PHP files are located), not the path to a PHP binary.
just in case you need only one server node and need to build around an node + php app i put here a method https://stackoverflow.com/a/68422021/5781320 that not involve this plugin (node-php) .so basically you can use node server and get post from a specific page(you can improve the node.js part , cause its only a prototype)

Express SSL redirect not working for root /

I use a wildcard match at the end of my Express route declarations to test if the connection is not HTTPS and if not, to redirect to the HTTPS version of the URI.
This works for everything except root, i.e., www.domain.com. This is a bit of a problem because domain.com serves a SPA.
app.get('*', function (req, res) {
if (req.headers['X-forwarded-proto'] != 'https') {
res.redirect('https://domain.com/#' + url_path);
}
else {
res.redirect('/#' + url_path);
}
});
I noticed that this chunk of code does not even get called when the URL is the root domain. I think this might be because I also declare:
app.use(express.static(path.join(application_root, 'public')));
This is necessary for the SPA to serve all of the assets. When I remove this line, my route handler is now called for the root domain, but my home page now infinitely redirects.
I had to create a custom route to server my SPA file, rename index.html so that Express would not try to serve it instead of my route.
To anyone who might still be struggeling with this, I had the same problem deploying my React-Express App on Heroku. I used a middleware: "heroku-ssl-redirect". The solution for me was to put this middleware up in the hierarchy (now its the first middleware I am applying):
var sslRedirect = require("heroku-ssl-redirect");
const express = require('express');
const path = require('path');
const e = require('express');
const app = express();
app.use(sslRedirect());
// Serve the static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));
// Handles any requests that don't match the ones above
app.get('*', (req, res) =>{
res.sendFile(path.join(__dirname+'/client/build/index.html'));
});
const port = process.env.PORT || 5000;
app.listen(port);
console.log('App is listening on port ' + port);

Is it possible to set a base URL for NodeJS app?

I want to be able to host multiple NodeJS apps under the same domain, without using sub-domains (like google.com/reader instead of images.google.com). The problem is that I'm always typing the first part of the url e.g. "/reader" in Express/NodeJS.
How can I set up an Express app so that the base URL is something.com/myapp?
So instead of:
app.get("/myapp", function (req, res) {
// can be accessed from something.com/myapp
});
I can do:
// Some set-up
app.base = "/myapp"
app.get("/", function (req, res) {
// can still be accessed from something.com/myapp
});
I'd also like to configure Connect's staticProvider to behave the same way (right now it defaults to serving static files to something.com/js or something.com/css instead of something.com/myapp/js)
The express router can handle this since 4.0
http://expressjs.com/en/api.html#router
http://bulkan-evcimen.com/using_express_router_instead_of_express_namespace.html
var express = require('express');
var app = express();
var router = express.Router();
// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use(function(req, res, next) {
console.log('%s %s %s', req.method, req.url, req.path);
next();
});
// this will only be invoked if the path ends in /bar
router.use('/bar', function(req, res, next) {
// ... maybe some additional /bar logging ...
next();
});
// always invoked
router.use(function(req, res, next) {
res.send('Hello World');
});
app.use('/foo', router);
app.listen(3000);
Previous answer (before express 4.0) :
The express-namespace module (dead now) used to do the trick :
https://github.com/visionmedia/express-namespace
require('express-namespace');
app.namespace('/myapp', function() {
app.get('/', function (req, res) {
// can be accessed from something.com/myapp
});
});
At the moment this is not supported, and it's not easy to add it on your own.
The whole routing stuff is buried deep inside the server code, and as a bonus there's no exposure of the routes them selfs.
I dug through the source and also checked out the latest version of Express and the Connect middleware, but there's still no support for such functionality, you should open a issue either on Connect or Express itself.
Meanwhile...
Patch the thing yourself, here's a quick and easy way with only one line of code changed.
In ~/.local/lib/node/.npm/express/1.0.0/package/lib/express/servers.js, search for:
// Generate the route
this.routes[method](path, fn);
This should be around line 357, replace that with:
// Generate the route
this.routes[method](((self.settings.base || '') + path), fn);
Now just add the setting:
app.set('base', '/myapp');
This works fine with paths that are plain strings, for RegEx support you will have to hack around in the router middleware yourself, better file an issue in that case.
As far as the static provider goes, just add in /mypapp when setting it up.
Update
Made it work with RegExp too:
// replace
this.routes[method](baseRoute(self.settings.base || '', path), fn);
// helper
function baseRoute(base, path) {
if (path instanceof RegExp) {
var exp = RegExp(path).toString().slice(1, -1);
return new RegExp(exp[0] === '^' ? '^' + base + exp.substring(1) : base + exp);
} else {
return (base || '') + path;
}
}
I only tested this with a handful of expressions, so this isn't 100% tested but in theory it should work.
Update 2
Filed an issue with the patch:
https://github.com/visionmedia/express/issues/issue/478
Just to update the thread, now with Express.js v4 you can do it without using express-namespace:
var express = require('express'),
forumRouter = express.Router(),
threadRouter = express.Router(),
app = express();
forumRouter.get('/:id)', function(req, res){
res.send('GET forum ' + req.params.id);
});
forumRouter.get('/:id/edit', function(req, res){
res.send('GET forum ' + req.params.id + ' edit page');
});
forumRouter.delete('/:id', function(req, res){
res.send('DELETE forum ' + req.params.id);
});
app.use('/forum', forumRouter);
threadRouter.get('/:id/thread/:tid', function(req, res){
res.send('GET forum ' + req.params.id + ' thread ' + req.params.tid);
});
forumRouter.use('/', threadRouter);
app.listen(app.get("port") || 3000);
Cheers!
I was able to achieve this using a combination of express-namespace for the routes and a fix from the below google group discussion for the static assets. This snippet will treat a request to /foo/javascripts/jquery.js like a request to /javascripts/jquery.js:
app.use('/foo', express.static(__dirname + '/public'));
Source:
https://groups.google.com/forum/#!msg/express-js/xlP6_DX6he0/6OTY4hwfV-0J
I know this is a very old question but Express has changed a lot since most these answers were posted so I thought I'd share my approach.
You can, of course, use Routers with Express 4 to group together related functionality behind a particular path. This is well documented and has already been covered by other answers.
However, it is also possible to mount an entire application at a particular path. As an example, let's assume our application (the one we want to host at /myapp) looks like this, in a file called myapp.js:
var express = require('express'),
path = require('path'),
app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/hello', function(req, res) {
res.send('Hello');
});
// Lots of other stuff here
exports.app = app;
In our main js file we could then mount this whole application at the path /myapp:
var express = require('express'),
app = express(),
myApp = require('./myapp').app;
app.use('/myapp', myApp);
app.listen(3000);
Note that we've created two applications here, one mounted on the other. The main application could have further sub-apps mounted at different paths as required.
The code in myapp.js is completely independent of where it was mounted. It's similar to the structure used by the express-generator in that regard.
Some documentation about sub-apps can be found here:
https://expressjs.com/en/4x/api.html#app.mountpath
https://expressjs.com/en/4x/api.html#app.onmount
There are also reliability issues. If reliability is important, a common solution is to use a front-end reverse HTTP proxy such as nginx or HAProxy. They both use single-thread evented architecture and are thus very scalable.
Then you can have different node processes for different subsites, and if one site fails (uncaught exception, memory leak, programmer error, whatever) the rest of sub-sites continue to work.
I was looking for this feature but for API routes, not for static files. What I did was that when I initialized the router, I added the mount path. So my configuration looks like this
//Default configuration
app.configure(function(){
app.use(express.compress());
app.use(express.logger('dev'));
app.set('json spaces',0);
app.use(express.limit('2mb'));
app.use(express.bodyParser());
app.use('/api', app.router); // <---
app.use(function(err, req, res, callback){
res.json(err.code, {});
});
});
Notice the '/api' when calling the router

Resources