Node.js routing with Apache proxy - node.js

I'm running Apache on a Linux server and find that my node.js apps routing doesn't work correctly when using URLS that go through Apache.
I followed instructions on other posts for turning on the proxy modules within apache and then set up this definition:
ProxyPass /testauth http://localhost:3000/
(I also had a line in there to define a similar reverse proxy that did nothing)
My node app runs on port 3000 with routing set up like in app.js
app.use('/', routes);
app.use('/tests', tests);
app.use('/questions', questions);
If I access URLs on my server like this:
http://rose.cs.umass.edu:3000/
http://rose.cs.umass.edu:3000/questions/179
I get correct results (note the styling with some simple CSS)
If I try to access thru apache like this:
http://rose.cs.umass.edu/testauth/questions/179
I get a 404 error but see from the backtrace that it is inside my js code.
For some reason the URL http://rose.cs.umass.edu/testauth partially works (but CSS doesn't get applied (because the index.ejs file includes the css like this:
<link rel='stylesheet' href='/stylesheets/style.css' />
The location of CSS files and the coding of relative paths follows all the node.js examples I have looked at and works fine in my development environment. But when running the app by going thru Apache, things are not working right.
Is there a fix to the apache config? Do I have to make an adjustment to how code paths in the my javascript and ejs files?

One clue I had to what was wrong is that node was printing the paths each time a request came in and they looked like
GET //questions/ 404 4.278 ms - 916
So I changed apache to have:
ProxyPass /testauth http://localhost:3000 (removed trailing slash)
Now the paths coming into my app were correctly formed.
The next order of business is to rework all the relative URLs in my EJS templates, client-side javascript, and even redirects in the server side.
Because I had to put "testauth" in the path so that Apache can forward to node, all the URLs coming into the app are of the form rose.cs.umass.edu/testauth/rest-of-url . This means relative URLs inside my app code that looked like
<a href="/questions" ....>
were now incorrect because they created absolute URLs that omitted the testauth in the path. Some of these relative URLs now are pretty strange (using things like ../ or even ../.. to get to things) . I wish there was a variable similar to ${pageContext.request.contextPath} that I use in JSP to build URLs.

I decided to mimic the JSP ${pageContext} idea
I added to file called config.js that has various settings that are particular to where the app is running (stuff like db credentials, etc). I added
// uncomment the line that applies
config.pageContext = "" // dev environment
// config.pageContext = "testauth" // production environment
My routing scripts all do something like:
res.render('questions', {pageContext: util.pageContext(req), questions: questionArray});
And the EJS templates all have stuff like this in the URLS:
<script src="<%= pageContext %>/static/js/bootstrap.min.js"></script>
A second alternative that I used for awhile until I went with the above:
Pass an argument to your node app when you start it. You then set a global variable similar to above and use it similarly. If you use a process manager (I use pm2) to run your node app on your server you might have to do something like:
pm2 start testauth -- -c /testauth // start testauth.bin using /testauth for the page context

Related

ExpressJS static file serve always serves the same file

I have a expressJs setup which looks like this:
// Imports...
const app: express.Application = express();
const port: number = 3001;
const listener = new StatementListenerAPI();
app.use('/listen', listener.getRouter());
app.use('/welcome', router);
if (fs.existsSync('./client')) {
// Running in prod environment with pre built client directory. Serve this.
app.use(express.static('./client'));
}
app.listen(port);
So I have some routers connected to the express app, and at the bottom I declare that the directory client should be served statically. This directory contains an index.html as well as lots of JS, CSS and PNG files. However, no matter which URL I try to access from the express server, it always shows the code of the index.html within the statically served directory. The references to the JS and CSS files used inside the index.html also just return the code of the index.html.
I am using ExpressJS 4.16.3
What am I doing wrong?
Edit: So technically it works if using __dirname + '/client' instead of ./client. What I am now getting is that, when making GET requests from e.g. Postman (therefore "hand-crafting" the HTTP requests), I am always getting the correct results. If I call the resources from within my web browser, it still always shows the website (resolves the index.html). However, now all resources like JS and CSS scripts are being resolved properly, so apperantly Chrome resolves those dependencies properly, I am just wondering why I am still getting the contents of index.html as result when requesting some of the assets or some of the express endpoints via Chrome. API calls via code are working fine, so its only why manual chrome requests show this weird behaviour, at this point I am only asking out of curiosity.
Answer to your original question:
The path supplied to express.static should be relative to the directory from where you launch your node process or an absolute path. To be safe construct an absolute path (ie from the current directory or file). For example:
app.use(express.static(__dirname + '/client'));
Regarding your followup question:
I assume this is because Chrome uses heavy caching and it thinks this folder should return the html file. You can try and reset all caches in Chrome, or just for the page.

Webpack somehow bypasses Express routing completely

I am starting from this excellent tutorial: https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/ and trying to extend it by adding a new page to serve through a new route. However after hours of mucking around I am realizing that somehow create-react-app is doing some weird magic (as mentioned in their docs here):
`create-react-app` configures a Webpack development server to run on `localhost:3000`.
This development server will bundle all static assets located under `client/src/`.
All requests to `localhost:3000` will serve `client/index.html` which will include Webpack's `bundle.js`.
The key quote is "All requests to localhost:3000 will serve client/index.html". I have no idea how this happens. So even though i mess around with routes/index.js:
app.route('/')
.get(function (req, res) {
res.sendFile(bipath.join(__dirname, '../public', 'THISCANBEANYRANDOMFILENAME.html'))
});
it doesnt matter because webpack is somehow directing localhost:3000 to index.html anyway. where and how is it doing this? Bottom line I am trying to modify my routes to serve a new html file and am running into all sorts of filepath issues (yes, even when i use require('path') or sendFile(...,{root: __dirname}).)
So what exactly is going on here and can you give me any hints to help me out?
Edit: this could be from babel as well as webpack - i'm not exactly clear where babel hands off and where webpack starts.
I haven't played around with create-react-app, but it seems like instead of using the default npm start, you could create your own server file and run that.
This looks like a good example.
https://medium.com/#patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d#.6y4rrl61q
Alternatively, if you're looking to have routes used as an api, you could proxy them to a different port like shown in the tutorial you linked.

Using Kraken for node, How can I apply localisation url to all routes (i18n)?

I have a node application using Kraken which uses i18n (makara) for localization and dust templates. I have defined many routes within the application which renders the en localisation correctly (being the default / fallback) without setting anything else up. e.g.
/help
/about
/test
...
I now want to also have localized url for easy sharing etc. being /:lang/help and as below returning the correct dust template:
/fr/help
/fr/about
/fr/test
Whats the ideal middleware to put in place to avoid having to edit each route i have already created?

How do I prevent Node.js / Express serving up my application's source code?

I never thought this would be a problem with Node.js and Express, but on a crazy whim I decided to type into a browser the location of one of the source files in my Node.js Express project - something like:
http://www.mywebsite.com/mynodejsapp/app.js
To my extreme horror, my application's source code popped right up, publicly available for all to see.
So, that aside: how do I stop it in Node.js / Express?
My setup code is pretty straightforward:
var app = express();
app.configure(function() {
app.use(express.static('/home/prod/server/app/public'));
});
app.listen(8888);
To clarify, this is what my folder structure looks like:
/home/prod/server/
/home/prod/server/app.js
/home/prod/server/public/
All sorts of various files that are intended for public access live under /public. All of my server source code lives under /server/, and my understanding of Express's static folder configuration is that the static folder is the only place that Express happily serves up files from the filesystem from.
Any ideas?
From what you posted it really smells like the URL you entered is served by e.g. Apache/nginx/... and you did put your node app within the document root. The answer is simple in this (and any similar) case:
You never put any of your sourcecode files within the document root or another HTTP-accessible folder. In your case, /home/prod/server/app/public should contain only client-side stuff (HTML, CSS, Graphics, (minified) client-side JS) and nginx should not have anything above this folder as its document root.

ExpressJS incorrectly rewriting paths when navigating directories

I've run into a maddeningly inconsistent issue with Express in a Node application where I am not able to correctly navigate through the built-in directory rendering due to a URL rewrite. It's easier to explain with code:
var express = require('express');
var app = express.createServer();
app.use("/public", express.static("/web/content"));
app.use("/public", express.directory("/web/content"));
app.listen(8888);
Using the uber-simple express server above the contents of /web/content are displayed as a list of links when you navigate to localhost:8888/public. So, for example:
..
index.html
header.jpg
js (folder)
css (folder)
From there if I click on index.html or header.jpg they display correctly, but clicking on the either folder will navigate to (for example) localhost:8888/js, even though the link clearly leads to localhost:8888/public/js. Upon further inpection it's revealed that the request is sent out for the right path (/public/js), but the server returns a 301 - Moved Permanently response that then redirects the browser to /js, which proceeds to display an error page because the content cannot be found. (No, really?)
Attempts to request a specific file beneath these folders (ie: localhost:8888/public/js/main.js) works fine and does not have the same issue.
The maddening part is that it was doing this on my dev box for a while and then simply... stopped. Not sure why. When attempting to deploy, however, the production server started having the same issue even though I can no longer reproduce it in my dev environment. Does anyone know why Express seems so intent on rewriting my URLs to the wrong thing?
Turns out the answer was pretty simple, and I only missed it because of my browser cache. After digging through the Express (well, technically Connect) code and sprinkling it liberally with console.log(), I traced it down to some code in the static middleware that was detecting that the directory contained an index.html file and was attempting to display that instead. Somehow that code got the wrong path, and the invalid redirect happened.
The real problem, though, was that the static handler was acting before the directory middleware could, which is a direct result of the order in which the middleware was declared. As such simply flipping the middleware declaration like so:
app.use("/public", express.directory("/web/content"));
app.use("/public", express.static("/web/content"));
fixed the issue.
Now, I had actually tried this before but did not realize that the 301 that I was sent previously had been cached, and so the browser was redirecting me before even touching the server. After flipping the order AND emptying my cache, I was able to navigate thde directory structure correctly.
Sigh If I had a dollar for every "bug" I've encountered caused by browser cache...

Resources