I'm using the Connect static middleware for Node.js in order to serve static assets in a web app I'm building. However, occasionally it fails to serve a static file, and instead sends the request through to my own server code, which looks like this:
var app = connect();
app.use(connect.static('public'));
app.use(function(request, response) {
var pathname = url.parse(request.url).pathname;
console.log(pathname);
...
});
So, in an ideal world, this code only logs the request if the static middleware doesn't catch a request to a static file first.
My directory structure in public looks like this:
public/
javascripts/
application.js
lib/
jquery-2.0.3.min.js
stylesheets/
screen.css
And in my html view, i'm grabbing these assets like so:
<script type="text/javascript" src="/javascripts/lib/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="/javascripts/application.js"></script>
<link rel="stylesheet" href="/stylesheets/screen.css" />
Connect has no trouble grabbing the /javascripts/application.js and /stylesheets/screen.css files, but it fails to fetch my jquery file in /javascripts/lib/, and this request is passed on to my server code, where the middleware should have caught and rendered it.
Clearly there's some sort of problem with Connect fetching the file from the subdirectory lib/, because I've already checked the file permissions on jquery-2.0.3.min.js and they are exactly the same as those on application.js.
Maddeningly, however, this bug appears to manifest itself entirely randomly. I'll start the server and it'll have the problem, but then when I restart the server it'll be gone. Then after making some unrelated change (I'm talking unrelated as in changing the CSS file slightly) on the app I'll start up the server and there it is again, and the error will remain and then go away after a few more restarts without any change to the code base.
As such, this is proving to be an incredibly difficult one to reproduce. If anybody has run into anything like this before, or has any idea what the problem might be, I would really really appreciate it.
If it helps at all, the nearest I can pinpoint the start of this error is this commit, in which I broke up an ejs template I wrote into partials to reuse the header and footer. I can't for the life of me tell how this might have started my problem, but maybe it might help someone diagnose the issue.
Related
I have been teaching myself Node.js by way of trial & error. I built a simple server using the Node.js HTTP class. I figured out that I can read a file asynchronously and serve the data using the asynchronous fs.readFile(..., cbk) callback method. What I don't understand at this point is how respond with all the other resources that the requests needs.
// "./index.js"
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res){
fs.readFile('index.html', function(err, data){
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
});
}).listen(8080);
For the sake of maintaining a single focus, I will use only Style-sheets as an example. Below is a super common link tag that demonstrates how I typically tell the server that the pages needs a specific CSS file. It works fine on the front-end side of things. But, how to I handle a request from a link tag on the the server's side of things (or on the backend)?
<link rel="stylesheet" type="text/css" href="/foo/bar/raboof.css">
Note: This is just a test project, but it doesn't use any frameworks, or even any modules (except for the dev-mod eslint). I would perfer to do this without 3rd party software/tools/frameworks etc...
Your nodejs server is not programmed to send any style sheets when the browser requests them.
A nodejs server, like you've created, serves NO files by default. It only serves files that you program it to serve. So, your nodejs server is programmed to do one thing and one thing only and that's to deliver index.html no matter what URL is requested from it.
So, here's what happens:
User enters some URL for your site
Browser sends your server a request for that page
Your web server delivers index.html
Browser parses index.html and finds style sheet links
Browser sends your server a request for a style sheet link
Your server sends it index.html
Browser realizes "that's not a style sheet" and you get no styles
So, for your HTML server to work properly, you have to add code to look at the requested URL and, if it's a style sheet URL, it needs to send the proper file for that stylesheet, not just blindly send index.html no matter what was requested.
Nobody says you need to use the Express library for this, but this is what it does. It makes it very easy to configure what gets sent when different types of requests are made. And, for requests of static resources like CSS files, it can even just be configured to automatically send them direct from the file system.
If you don't want to use Express for this, you don't have to, but then you will have to write your own code to serve the right data when different URLs are requested.
If you want to write your own code for this, you will have to create some sort of if/else or switch statement or table lookup that looks at req.url and then send the appropriate content that matches the requested URL. Then, when the browser requests your style sheet, you can actually send it the appropriate style sheet, not index.html. The same would be true for Javascript files, images, page icon, ajax requests or any resource on your server that your page references.
Because your server-side code is written to handle all.http requests and deliver the same html content, regardless of the path.
try adding some if-else logic inside your handler, and deliver appropriate file based on the request path.
something like:
if(req.path === "" || req.path === "index.html")
fs.read htnl file here
else if (req.path==="my.css")
fs.read css file
learn to use browser dev tools (F12), which shows you exactly which requests the browser is making, what it sends, what it gets back - amongst many other things.
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.
I am messing around with express.js and have built some basic functionality but am having issues with express static serving from the wrong place if the URL is longer than one directory from root. See the examples below.
I am using the normal documented approach to using static.
app.use(express.static(__dirname + '/public'));
And have set up a couple of routes. eg.
app.get('/signup', function(req, res) {
res.render('signup.ejs');
});
With a 404 catch at the end of the chain.
app.get('*', function(req, res){
res.status(404).render('404');
});
If I hit page such as localhost:3000 or localhost:3000/login which are defined routes, all is well. Even if I hit an undefined route of localhost:3000/foo, I get the 404 rendered correctly with all images present.
However if I go one further and do something like localhost:3000/login/foo all the images are missing and I will get an error in the browsers console with the following address.
http://localhost:3000/login/img/site-brand.png
This happens the same on routes defined with more than one directory too.
I interpreted the docs on the express website that regardless of what was calling for the static image it would be served from the public directory in root, which contains a js, img, and css directories.
My questions are, what have I misinterpreted? and how do I get express to always serve relative to root?
I wrote the whole question then realised that when I had set up the src="" tags in my .ejs files I had used relative paths, not absolute. Rather than delete the question I decided to answer it and post it for others.
So instead of using src="img/my-image.png" it should be src="/img/my-image.png" The leading slash indicates that the request is relative to root not the path that is making the request.
Basic web development stuff there. I should have seen it first time out but its late, and I am cramming my head full of new frameworks which is in turn squeezing the more trivial stuff out of my small brain.
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.
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...