I have a directory structure like this
root
private
js
css
index.html
app.js
privateRouter.js
...
In my index.html I reference the js and css files using relative path like this:
<link rel="stylesheet" href="css/index.css"/>
<script src="js/index.js"></script>
On the server side I have a private router checks for authentication before serving these files:
In app.js:
app.use("/private", privateRouter);
in privateRouter.js:
router.use((req, res, next) => {
isAuthenticated(req) ? next() : res.redirect("/");
});
router.get('/', function(req, res, next) {
res.sendFile(require('path').join(__dirname + "/private/index.html"));
});
So now if I visit http://mywebsite.com/private I will get the the index.html, but the request of js/css files from the browser comes back to the server as http://mywebsite.com/js instead of http://mywebsite.com/private/js, thus returns file not found.
Alternatively if I serve files statically, the browser knows to request from /private/js:
app.use("/private", express.static(path.join(__dirname, 'private')));
But I can't server statically because I need to authenticate specific files and not serve all files publicly. And I don't want to have to append private/ before all file references on client side. I don't understand why when serving statically the server knows to use /private as root but when using a router it uses / as root.
How can I keep the url as http://mywebsite.com/private while not having to append private/ in all file references on the client side?
I'm new to express.js and it was also difficult for me to formulate the question. I think I'm fundamentally misunderstanding something about express.js works. Thanks for your help!
You can modify a request's URL using middleware for internal routing:
app.use((req,res,next)=>{
req.url = "/private" + req.url; // prepend "/private" to the url
next();
});
You can also set the base URL using the base tag, which means you only need to specify the base URL once per page.
<html>
<head>
<base href="private">
<link rel="stylesheet" href="css/index.css"/>
<script src="js/index.js"></script>
</head>
</html>
This should then send the requests to:
/private/css/index.css
/private/js/index.js
However, you will still need code to handle these paths, otherwise, you will still get the 404 not found error.
Related
I am using express and I would like to redirect to another file since my server is not always up and running. I can not understand why I am receiving a HTML document when my file is JSON. It looks like it gets redirected, but the result is wrong. I can see that my page is redirected from the old URL to the new URL. So it looks like that part is working. But I am not receiving my local json-file in the response.
What I have in my server index.js file:
app.use('/my/original/url', (req, res) => {
res.writeHead(302, { location: '/mock/mockedresult.json' });
res.end();
});
I found out that I need to make my mock folder available. I did so by adding this line of code above the code snippet in my question:
app.use('/mock', express.static(resolve(process.cwd(), 'server/mock')));
var app = require('express')();
app.get('/', function(req, res) {
res.sendFile(__dirname + "/" + "index.html");
});
<link rel="stylesheet" href="style.css">
I used the above Node.js code to send a html file. To get the html file formatted I need to send another css file (style.css).
My question is: How can I send both of these two files (index.html and style.css) using sendFile() and integrate them together in the client side?
The browser should load style.css on its own, so you can serve that as a route:
app.get('/style.css', function(req, res) {
res.sendFile(__dirname + "/" + "style.css");
});
However, this would get very cumbersome very quickly as you add more files. Express provides a built in way to serve static files:
https://expressjs.com/en/starter/static-files.html
const express = require("express");
const app = express();
app.use(express.static(__dirname));
Keep in mind that if index.html is in the same directory as your server code you will also serve the server code as static files which is undesirable.
Instead you should move index.html, your css, images, scripts, etc. to a subdirectory such as one named public and use:
app.use(express.static("public"));
If you do this, Express will serve index.html automatically and you can remove your app.get("/" as well.
See, I was training with Node (and TS btw), and tried to do a trivial server with multiple request/response options. But I have a problem I don't know how to solve without using Express (at least for now I don't want to use it).
I have a HTML file which requests an image file. While in the IDE, everything looks like it's going to work, but when the server is running, the image cannot be found. It's kind of obvious why: The HTML makes a request the server doesn't know how to handle. Thing is, I thought the document could refer to other files without the need of talking to the server.
What is an elegant and working solution for my problem?
Thanks in advance.
import * as http from 'http'
import * as fs from 'fs'
fs.readFile('doc/kmCNHkq.jpg', function (err, data) {
let binaryimg = new Buffer(data).toString('base64');
if (err) throw err;
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'image/jpeg'});
res.end(data);
console.log("Delivered the jpeg");
}).listen(8000);
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(binaryimg);
console.log("Delivered base64 string");
}).listen(8124);
console.log("Unless bug, both servers are listening");
});
fs.readFile('doc/index.html', function(err, data) {
http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data)
}).listen(80);
console.log("HTML server is running")
})
(main.ts; Targets ES6)
<html>
<head>
</head>
<body>
<img src="doc/kmCNHkq.jpg"/>
</body>
</html>
(index.html)
Observation: I used to leave the HTML file in '../doc/' and resources on '../img/' however it seems that the HTML uses relative paths, so I copied the image into HTML's folder. If the solution also made it so I could leave the resources on their's respective folders it would be much appreciated.
#Edit:
Now I'm using this switch/case request handler. Working as expected, the HTML's request for the image is interpreted as a normal request (which may not end up scaling well, idk, but screw it). Thanks a lot!
import * as http from 'http'
import * as fs from 'fs'
var stream: fs.ReadStream,
folder = __dirname.substr(0, __dirname.length - 3);
http.createServer(function(req,res) {
switch (req.url){
case('/jpeg'):
stream = fs.createReadStream(folder + 'img/kmCNHkq.jpg');
stream.pipe(res);
console.log("Delivering the jpeg");
break;
case('/base64'):
fs.readFile('img/kmCNHkq.jpg', function (err, data) {
let img64 = new Buffer(data).toString('base64');
if (err) throw err;
res.end(img64);
console.log("Delivered base64 string");
})
break;
case('/html'):
stream = fs.createReadStream(folder + 'doc/index.html');
stream.pipe(res);
console.log("Sending the docs");
break;
default:
console.log("Shit happens");
}
}).listen(80)
(main.ts)
<html>
<body>
<img src="jpeg"/>
</body>
</html>
(index.html)
Short answer:
You won't be able to refer to specific resources on the server (such as your image) unless your server knows how to respond to those requests for that content. It looks like you can probably make your example work easily immediately though by changing the image src to just http://localhost:8000 though.
Longer answer:
Using 'doc/kmCNHkq.jpg' as the src for your image tells your browser that when it loads the page, it should go to the server it got the page from, and ask it for the 'doc/kmCNHkq.jpg' resource. If you specify a full URL including the protocol (the http://) then it will be absolute, instead of relative, so you can request from a different server than the one that served the page.
The servers that you've written don't actually look at the path of the file that's requested though (req.url), and actually they just always return the same content. If you connect to http://localhost:80 (the third server you've created above), and do request that jpg you'll still just get given the same HTML data of the page, because it just runs the two lines in your createServer call at the end of your example. You have written a server that always returns the image however above (the first server), just running on a different port, which is why the above solution works.
Just using that existing server is the simplest solution. The far more conventional approach though is to have just a single HTTP server running on a single port (instead of the 3 you have) and to use req.url to decide what data to return.
Traditionally for static content that means mapping a requested path directly onto the layout of the files on disk, so that requesting doc/abc.jpg looks for a doc folder in the server's directory, and returns the data from abc.jpg therein. That's not required necessarily at all though, and your server can interpret those paths however you like, to return content from anywhere.
(Note than none of this is really anything to do with TypeScript, or even much to do with Node.js. This is really just the essentials of how HTTP servers and browsers interact, and it would be almost identical with any other backing technology. I'd take a look more into the general HTTP and browser details if you're looking to get more background on this.)
I am trying to configure my browserHistory. My route is
<Route path="/test" component = {App} />
It works fine if I create a link. But if I put localhost/test in the browser or url I get a 404 error. I assume it cant find it on the server.
Can someone please help me? I am new to react-router. Do I have to configure the server side?
Thank you so much in advance.
Yes, as mentioned in React Router documentation you must configure your server so that it always returns your index page, no matter which path the browser requests.
Using express, supposing you have a /public/index.html file, this would work:
/* Your express includes and init code would go here... */
// Serve static assets normally
app.use(express.static(__dirname + '/public'))
// Handle every other route with index.html, which will contain
// a script tag to your application's JavaScript file(s).
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})
The important thing is app.get('*', ..., which will return the same thing (in this case your index.html file), no matter which path is requested from your browser.
Hope that helps.
I have a Linux webserver using node which hosts a directory containing a static index.html file. I am wondering how I can make it so a user getting to the correct URL does not rely upon case sensitivity.
Currently, server.com/caa/ points to something different than server.com/CAA/ -- the directory holding index.html is lowercase "caa"
Have you tried adding some middleware that coverts all urls to lower case? Heres an example of one way of doing this
app.use(function(req, res, next) {
req.url = req.url.toLowerCase();
next()
});