Simple node.js server that sends html+css as response

38,000

What you have written in your first snippet is a web server that responds with the body of your HTML file regardless of what URI the browser requests.

That's all nice and well, but then with the second snippet, you're trying to send a second document to a closed response handle. To understand why this doesn't work, you have to understand how HTTP works. HTTP is (for the most part) a request->response type protocol. That is, the browser asks for something and the server sends that thing, or an error message of some sort, back to the browser. (I'll skip over keep-alive and methods that allow the server to push content to the browser--those are all far beyond the simple learning purpose you seem to have in mind here.) Suffice it to say that it is inappropriate to send a second response to the browser when it hasn't asked for it.

So how do you get the browser to ask for a second document? Well, that's easy enough... in your HTML file you probably have a <link rel="stylesheet" href="AppClientStyle.css"> tag. This will cause the browser to make a request to your server asking it for AppClientStyle.css. You can handle this by adding a switch or if to your createServer code to perform a different action based on the URL the browser requests.

var server = http.createServer(function (request, response) {
    switch (request.url) {
        case "/AppClientStyle.css" :
            response.writeHead(200, {"Content-Type": "text/css"});
            response.write(cssFile);
            break;
        default :    
            response.writeHead(200, {"Content-Type": "text/html"});
            response.write(htmlFile);
    });
    response.end();
}

So, first, when you access your server at http://localhost:8000 you will be sent your html file. Then the contents of that file will trigger the browser to ask for http://localhost:8000/AppClientStyle.css

Note that you can make your server far more flexible by serving any file that exists in your project directory:

var server = http.createServer(function (request, response) {
    fs.readFile('./' + request.url, function(err, data) {
        if (!err) {
            var dotoffset = request.url.lastIndexOf('.');
            var mimetype = dotoffset == -1
                            ? 'text/plain'
                            : {
                                '.html' : 'text/html',
                                '.ico' : 'image/x-icon',
                                '.jpg' : 'image/jpeg',
                                '.png' : 'image/png',
                                '.gif' : 'image/gif',
                                '.css' : 'text/css',
                                '.js' : 'text/javascript'
                                }[ request.url.substr(dotoffset) ];
            response.setHeader('Content-type' , mimetype);
            response.end(data);
            console.log( request.url, mimetype );
        } else {
            console.log ('file not found: ' + request.url);
            response.writeHead(404, "Not Found");
            response.end();
        }
    });
})                         

Start this in the same directory as your HTML and CSS files. The above is simplistic, error-prone and INSECURE. But it should be sufficient for your own learning or local development purposes.

Keep in mind that all the above is far less succinct than just using Express. In fact, I'm not sure why you wouldn't want to use Express, so I'm going to try to convince you to try it:

$ npm install express
$ mkdir www
$ mv AppClientStyle.css www/
$ mv AppClient.html www/index.html

Your script will look like: (Borrowed from Express Hello World)

var express = require('express')
var app = express()

app.use(express.static('www'));

var server = app.listen(8000, function () {

    var host = server.address().address
    var port = server.address().port

    console.log('Express app listening at http://%s:%s', host, port)

})

Then run your script and point your browser to http://localhost:8000. It really is that painless.

Share:
38,000
kiluk876
Author by

kiluk876

Updated on July 09, 2022

Comments

  • kiluk876
    kiluk876 almost 2 years

    I've created basic http server that sends html file as response. How can I send css file as well so client using browser will see a html using css ?

    The code I have:

    var http = require('http');
    
    var fs = require('fs');
    var htmlFile;
    
    fs.readFile('./AppClient.html', function(err, data) {
        if (err){
            throw err;
        }
        htmlFile = data;
    });
    
    
    
    var server = http.createServer(function (request, response) {
          response.writeHead(200, {"Content-Type": "text/html"});
          response.end(htmlFile);
        });
    
    //Listen on port 8000, IP defaults to 127.0.0.1
    server.listen(8000);
    
    
    console.log("Server running at http://127.0.0.1:8000/");
    

    What I have tried(it seems it does not work - client sees only css file content here):

    var http = require('http');
    
    var fs = require('fs');
    var htmlFile;
    var cssFile;
    
    fs.readFile('./AppClient.html', function(err, data) {
        if (err){
            throw err;
        }
        htmlFile = data;
    });
    
    fs.readFile('./AppClientStyle.css', function(err, data) {
        if (err){
            throw err;
        }
        cssFile = data;
    });
    
    var server = http.createServer(function (request, response) {
          response.writeHead(200, {"Content-Type": "text/css"});
          response.write(cssFile);
          response.end();
    
          response.writeHead(200, {"Content-Type": "text/html"});
          response.write(htmlFile);
          response.end();
        });
    
    //Listen on port 8000, IP defaults to 127.0.0.1
    server.listen(8000);
    
    
    console.log("Server running at http://127.0.0.1:8000/");
    

    html file:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <link rel="stylesheet" type="text/css" href="AppClientStyle.css">
    </head>
    <body>
    
    
    <div class=middleScreen>
    
    <p id="p1">Random text</p>
    
    </div>
    
    </body>
    </html>
    

    css file :

    @CHARSET "UTF-8";
    
    .middleScreen{
        text-align:center;
        margin-top:10%;
    }
    

    I don't want to use express here(it is just for learning purpose)

  • kiluk876
    kiluk876 about 9 years
    Now that is the answer I was waiting for. Why I didn't want to use express? - because I wanted to understand basics before switching to using framewrok. Thanks for help
  • Dan Bechard
    Dan Bechard over 8 years
    The first one doesn't work without some type of URL routing. The server doesn't know what to do with the "styles.css" request unless you tell it. That's the entire premise of the question.
  • Alex
    Alex about 4 years
    Thanks! This was very helpful after I spent over and hour researching the same error.
  • FireVortex
    FireVortex over 3 years
    Thank you, I always try to use node.js without 3rd party but you opened my eyes.
  • Nicholas Stom
    Nicholas Stom about 2 years
    You mention that the native Node.js (without Express) way to do this is insecure. Would you explain what you mean? Thanks!