I use node js without frameworks etc. and I have problem, I don't understand how set "start html page" for my first request to server.
I tried do it like this
var server = new http.Server();
server.listen(1137, '127.0.0.1');
server.on('request', function(req, res) {
fs.readFile('../public/index.html', function (err, html) {
if (err) {
throw err;
} else {
res.write(html);
res.end();
}
});
});
When I do request to 127.0.0.1:1137 - I got html in browser, but links to CSS/JS files isn't correct and how I can this to fix I don't know :(
I want get the html page ../public/index.html in browser when I will do first request to my server.
my server location
project/server/server.js
my html-page location
project/public/index.html
Your page includes references to images and stylesheets, which you said don't work.
Well, you are responding to every single HTTP request with the contents of the specified HTML page.
When the browser parses the HTML, it will see the image and stylesheet links and issue HTTP requests to those URL's. But those URL's don't respond with images or stylesheets. They respond with HTML.
GET /index.html
yields
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<img src="someimage.png">
</body>
</html>
The browser then requests
GET /styles.css
yields
<html>
...
</html>
The browser then requests
GET /someimage.png
yields
<html>
...
</html>
You need to make the response conditional based on the request. To prevent disclosure of information, like #minitech mentioned, you need to be careful not to blindly concatenate the paths. Then you have to worry about MIME types.
You're really best off using a framework like express.
You will need to return different files, depending on the path that was requested.
On the 'request' handler you are getting a ClientRequest object, which has a path property. Use this information to return the correct files (index.html, the CSS or JS files...). An example request callback could be:
function onRequest(req, res) {
var path = req.path;
fs.readFile('../public' + path, function(err, contents) {
if (err) {
res.writeHead(500);
res.end(err);
return;
}
res.end(contents);
});
}
This is still very basic, you will probably want to handle non-existent files with a 404 result code, return the correct Content-Type headers the different file kinds (text/html, text/css, etc).
Update: as minitech recommends, the path should be checked for ../, which would go up the filesystem and access sensitive files.
Hope this helps.
Related
My question can be pretty similar to others, but I already read a lot of answers, but I don't understand completely the details behind them.
I have to create a node.js REST API, but I don't took any lessons before. So i'm currently reading and trying tutorials to learn to create a simple node.js script.
I installed node.js, i created my script (it's just reading an input field), and when i click on a button, it's supposed to write the input in the console.
The tutorial needs only node.js, and use the .createserver. I understand that node.js is server side and can't be interpreted without it.
The tutorial asks to open the .html file in the browser, directly with the path. The html webpage shows up, but... When i'm pressing "ok", here's the errors :
*app.js:1 Uncaught ReferenceError: require is not defined
Access to XMLHttpRequest at 'file:///.../ApplicationAngular/nodeProject/app.html?name=' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
GET file:///.../ApplicationAngular/nodeProject/app.html?name= net::ERR_FAILED*
All the threads on StackOverflow explains that I need a third-party to run the HTML webpage. But on the tutorial, everything is working fine and never mentions the existance of Express, Cheerio, etc..
Here's the samples of code:
app.html
<input type="text" placeholder="Enter your name" id="name"/>
<input type="button" value="OK" onclick="valid()"/>
<div id="message"></div>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="app.js"></script>
<script>
function valid() {
$.get('', { name: $('#name').val() }, function(data) {
$('#message').html(data.message);
}, 'json');
}
</script>
app.js
var http = require('http');
var url = require('url');
var fs = require('fs');
var server = http.createServer(function (req, res) {
var url_parts = url.parse(req.url, true);
var name = url_parts.query.name;
if(name){
console.log('Nom: ' + name);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify({message: 'Hello' + name + ' !'}));
} else {
console.log('No name !');
res.writeHead(200, {'Content-Type': 'text/plain'});
fs.readFile('app.html', function (err,data)
{
res.end(data);
});
}
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
Is the tutorial missing something? Do I have to install Express in order to view the page web?
Sorry again, english is not my native langage.
Thanks a lot for your answers.
With this line in your html
<script src="app.js"></script> <!-- wrong! -->
you try to run your nodejs program in your browser's javascript interpreter. You need to run it on your server instead. Your browser gacks on the require() operations because those are made to work in nodejs on your server.
Try removing the line from your html, and try doing something like this on your server's command line, then visiting http://localhost:1337 from your browser.
node app.js
The fact that browsers and nodejs support the same language is a bit confusing as you figure this all out. The language is the same but the two runtime environments are quite different. Be patient. You'll get it.
The app.js nodejs program you showed us should function correctly. In its if (name) branch it handles the request coming from the $.get() operation in the browser. In its else branch it delivers the html file to the browser.
And, it has to be said, doing more than just this kind of tutorial with nodejs alone -- without express or some other webserver framework -- gets to be a huge pain in the xxx neck, enough of a pain in the neck that you'll be tempted to develop your own framework.
Edit You have this line twice
res.writeHead(200, {'Content-Type': 'text/plain'}); /* wrong! */
Change both occurrences to
res.writeHead(200, {'Content-Type': 'text/html'});
The Content-Type: text/html header tells your browser to interpret your html file as html, not raw text.
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 building a single page web application with Ember.js or Backbone.js as front end MVC, express.js(node.js) as back end server.
server/app.js code in short
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, '..', 'client')));
app.get('*', function(req, res) {
return res.render('base'); (will sendFile (client/index.html) )
});
It will load up the client/ folder with all the public assets, client folder structure looks like this
- client
-- index.html ( will be rendered as always )
-- app (front end mvc code)
-- assets
-- images
-- styles
When html5 pushstate is enabled by front end MVC, express server is always serving all the matching route as well, which in turn render index.html as always when page is refreshed or url is being manually inserted in the browser.
client/index.html (sample code)
<link rel="stylesheet" href="assets/styles/reset.css">
<link rel="stylesheet" href="assets/styles/base.css">
Here are three different URLs cases
localhost:3000/ (root)
localhost:3000/users || localhost:3000/#/users (hard url)
localhost:3000/users/1 || localhost:3000/#/users/1 ( dynamic segment)
When I defined any static resource as relative path, it works on matching path with root url and hard url on page refresh, it serves resources as
GET /assets/styles/reset.css 304 1ms
GET /assets/styles/base.css 304 2ms
But when I got to localhost:3000/users/1 and refresh the page, I got the wrong resource url, so it failed on loading client/index.html since there are no resources in that path.
GET /users/assets/styles/reset.css 304 2ms
GET /users/assets/styles/base.css 304 6ms
Then I switched to absolute path in
client/index.html (sample code)
<link rel="stylesheet" href="/assets/styles/reset.css">
<link rel="stylesheet" href="/assets/styles/base.css">
it works well even in the dynamic segment url localhost:3000/users/1, all resource serve in the correct url path. but I have an html img tag <img src="assets/images/icons/star.png" alt="star"> in front end mvc template which will be rendered when application boots up. When I load up localhost:3000/users/1 on page refresh, here is what I get
GET /assets/styles/reset.css 304 1ms
GET /assets/styles/base.css 304 2ms
GET /users/assets/images/icons/star.png 304 5ms
I tried with absolute path and relative path in front end mvc template (<img src="/assets/images/icons/star.png" alt="star">), it loads with users prefix no matter what.
I found a solution by tbranyen, but it did not quite work for me. I do not need to setup any cluster at all, what I want is my express server to serve any resource without any prefix when any dynamic segment is being matched. So I wrote this middleware, and it fires correct but still loads the static resource with users/ prefix.
// this route uses the ":user" named parameter
// which will cause the 'user' param callback to be triggered
router.get('/users/:user_id', function(req, res, next) {
console.log('req.params: ', req.params.user_id );
//console.log('#TODO: need to handle the params here');
//next();
return res.render('base');
});
Problem:
When using Express.js as a server, I want every browser request will be handled with response client/index.html, even with dynamic query segment. Currently, whenever url query involves with dynamic query segment /users/:user_id, the response from express server will prefix with users to all the static resources.
For example, when I load the url with dynamic segment localhost:3000/users/1. if i have a resources assets/images/icons/star.png in handlebars template, express server response back /users/assets/images/icons/star.png, but I do not have users folder with the assets. What I want response back /assets/images/icons/star.png.
I tried with absolute path /assets/images/icons/star.png or relative path assets/images/icons/star.png in the handlebars template, it always return with users prefix in the response.
Thanks for any help!
In the <head> of your base template, add this toward the top:
<base href="/">
i currently have transmission-daemon web ui served by nginx
server {
listen 2324;
server_name torrent.example.com;
location /rpc {
proxy_pass http://127.0.0.1:9091/transmission/rpc;
}
location /transmission {
proxy_pass http://127.0.0.1:9091/transmission;
}
location / {
proxy_pass http://127.0.0.1:9091/transmission/web/;
}
}
i am trying to display this page via https://github.com/stormpath/stormpath-express-sample this dashboard/user interface
in routes/index.js i have
router.get('/torrent', function (req, res, next) {
if (!req.user || req.user.status !== 'ENABLED') {
return res.redirect('/login');
}
var newurl = 'http://127.0.0.1:2324'
request(newurl).pipe(res)
});
i see the html when i goto /torrent but no images/css/js i am thinking the request is not the right tool for this purpose could some one offer a better solution
many thanks
Your HTML probably refers to CSS/images/etc using URLs such as /index.css. The browser makes these into fully-qualified URLs that look like http://torrent.example.com/index.css, which is not proxied by ngnix the way you have it set up.
You probably want to either use URLs such as /transmission/index.css for your CSS (when specified in the HTML), or alternatively have a <base> tag in your HTML for that.
ok so i have made progress with html/css i moved the transmission interface into the express root and imported the html into jade but now i am having a new problem
when i load the /torrent page i can seen in the web console it makes a request to /rpc which i have made a route for
router.get('/rpc|/rpc/', function (req, res) {
var newurl = 'http://127.0.0.1:9091/torrent/rpc/'
request(newurl).pipe(res)
});
but this comes up with a 404 when i change router.get to router.post i get a 405 error
i have removed the 409 error from transmission so this should work
i have solved the issue
i imported the transmission index.html into a jade template
i routed /torrent to render that template
then i made a new route for /rpc|/rpc/ made that do a post request to the backend transmission-daemon
i also changed /js/remote.js to look for the RPC._Root at the atchual domain
This is really weird problem. I just installed Node.JS on my system (Fedora).
I have three files in /var/www/mirror/:
server.js
client.js
index.html
File server.js is the one I call via CLI: node server.js.
It, basically, returns index.html.
var
http = require('http'),
io = require('socket.io'),
fs = require('fs');
http.createServer(function(request, response) {
fs.readFile(__dirname + '/index.html', function(error, data) {
if (error) {
result.writeHead(500);
console.log('Error: Could not read index.html.');
}
response.writeHead(200, {'Content-Type': 'text/html'});
response.end(data);
});
}).listen(1337, '127.0.0.1');
console.log('Server is running.');
All works as expected and no errors are thrown anywhere.
In index.html I have simple HTML5 structure (nothing unnecessary, really!) and <script /> that points to, already mentioned, client.js.
That line of code looks like this (Ctrl + U; from browser):
<script src="client.js"></script>
By moving cursor on client.js, I got actual location: http://127.0.0.1:1337/client.js.
Seems correct, right?
The problem:
By opening that link it opens wanted file, but the content is as server.js should return.
This disallows me from including any internal scripts and style-sheets!
I guess that anything that goes via http://127.0.0.1:1337/ (also http://127.0.0.1:1337/client.js, http://127.0.0.1:1337/a/b/c etc.) is handled via server.js - and server.js returns index.html (see above).
How can I fix it? Thanks in any advice!
Look at the req.url to tell you the url that the user is requesting. From there, you have to have some code decide whether to serve index.html or client.js.
Also, since I'm guessing index.html isn't changing very frequently, you should probably just read it once, and store the buffer in a variable, rather than reading it on every request.
There are some modules that make serving static files a bit easier. Check out filed for a pretty nice standalone static file