Take the tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am coming from a (traditional) server side scripting (PHP) background and am trying to experiment with Node to see what the fuss is all about.

Objective: serve up a simple web document with some style sheets and scripts on it.

My node.js script:

var http = require('http');
var fs = require('fs');

fs.readFile('index.html', function (err, html) {
    if (err) {
        throw err; 
    }       
    http.createServer(function(request, response) { 
        response.writeHeader(200, {"Content-Type": "text/html"});  
        response.write(html);  
        response.end();  
    }).listen(1337, '127.0.0.1');
});

index.html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'> 
        <title>Node.js test</title>
        <link rel="stylesheet" media="screen" type="text/css" href="css/plugin.css" />
        <link rel="stylesheet" media="screen" type="text/css" href="css/xGrid.css" />
        <link rel="stylesheet" media="screen" type="text/css" href="css/jquery-ui/jquery-ui-1.10.1.custom.min.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
        <script src="js/slate.js"></script>
        <script src="js/slate.portlet.js"></script>
        <script src="js/slate.message.js"></script>
        <script src="js/plugin.js"></script>
    </head>
    <body>
        <h1 class="styled-h1">Test</h1>
    </body>
</html>

The problem I am facing:

The two script includes coming from the Google CDN are loaded on to the document fine. However, every other style sheet or script being called from my local file system get interpreted as text/html and so don't have the intended effect. Here is a screenshot from Google Chrome console:

enter image description here

I want to understand why this is happening.

PS: I know I can use a framework like Express to make things easier but I want to get a hold of the fundamentals first.

share|improve this question
1  
I wrote a module called Cachemere which lets you do this. It also automatically caches all your resources. Link: github.com/topcloud/cachemere –  user1181615 Nov 25 at 5:16
add comment

4 Answers

up vote 2 down vote accepted

Simple: you're setting the Content-Type header to text/html, always. Also, it will always serve your index.html file. Look:

fs.readFile('index.html', function (err, html) {
    if (err) {
        throw err; 
    }       
    http.createServer(function(request, response) { 
        response.writeHeader(200, {"Content-Type": "text/html"});  // <-- HERE!
        response.write(html);  // <-- HERE!
        response.end();  
    }).listen(1337, '127.0.0.1');
});

You should parse the URL, look up what file you want to require, read its contents and write them to the response if it exists, otherwise serve an 404 error. Also, you'll need to set the correct headers.

So, do you still want to do it at your own?
At least, try something like send, which is a basic static file server.

share|improve this answer
add comment

Your server is responding to all request with a unique response... When the browser request for CSS and Scripts, your server do the only thing he knows !!!

share|improve this answer
add comment

You are creating a web server that does one thing and one thing only irrespective of what path or parameters are sent: it serves your HTML file index.html with MIME type text/html.

The requests for CSS files are relative path requests, i.e. when the web browser sees the instruction to load css/plugin.css it calls your web server with a new path; but your web server ignores the path and just returns index.html again with MIME type text/html. Your web browser throws errors about the wrong MIME type but what it didn't tell you was that you just loaded index.html again.

To confirm for yourself click on the following link: http://127.0.0.1:1337/css/plugin.css

I wouldn't pick a port of 1337 until you've earned the "elite" badge. Frankly it is embarrassing when asking a question of this nature.

share|improve this answer
add comment

I ran into the same problem a while ago, and spent quite a while on it. Google searches were no good. However, at while thinking about it, I noticed then when you use writeHead, you are intially told to use a content type of "text/plain". Upon digging further, it became apparent that you could also use "text/html". Then, I decided to experiment with a dynamically assigned content type - because a content-type of text/html wouldn't handle js or css files. Finally, I have managed to get it working. Now, I like working in modules, so sorry for the rather moduled code. The following code can be used to serve almost anything, as far as I have tested.

The following was the test html

index.html

<html>
<head>

<title>Website</title>
<link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>

    <h3>Website</h3>
</body>


</html>

The following is the linked css file

style.css

body {

    background-color: green;
    text-align: center;
}

The following are the modules of node that were used to create the server.

index.js

console.log("Creating server");

// Gets the required components
var server = require("./server.js");
var router = require("./router.js");
var pageserver = require("./pageserver.js");

// Starts the server.
server.Start(router.route, pageserver.serve, pageserver.reqtype);

server.js

var http = require("http");
var url = require("url");

// Starts the server
var Start = function(route, serve, reqtype) {

    // Lauched when there is a request.
    var onRequest = function(request, response) {

        // Extracts the pathname from the url
        var pathname = url.parse(request.url).pathname;

        // Removes the starting "/". If this fails, then that means the request
        // was without
        // the "/", and so does not affect it.
        try {
            pathname = pathname.substring(1, pathname.length);
        } catch (err) {

        }

        // Responds to all requests apart from that for favicon.ico
        if (pathname !== "favicon.ico") {

            console.log("Request has been recieved");

            // Gets the path from the router
            var path = route(pathname);
            console.log("Path has been generated");
            // Gets html or whatever will be written from the pageserver
            var html = "";

            html = serve(path);
            console.log("Html has been generated");

            // Gets the type from the pageserver
            var type = reqtype(path);
            console.log("Filetype has been found");

            // Writes what type of data will be sent. Dynamically sets file
            // ending.
            response.writeHead(200, {
                "Content-Type" : "text/" + type
            });
            // writes to output
            console.log("Writing to output");
            response.write(html);
            console.log("Written to output");
            // ends connection
            response.end();
            console.log("Request answered successfully");
        }

    };

    http.createServer(onRequest).listen(8888);
    console.log("Server has been started");
};

exports.Start = Start;

router.js

var path = require("path");

// Routes the request, so that a proper file can be found for it.
var route = function(pathname) {

    var path = process.cwd() + "\\"; // Sets up the path to the
    // current directory, the one
    // that will contain the pages.

    // If the file ending has been corrected before hand
    var corrected = false;

    if (pathname === "" || pathname === "index" || pathname === "home"
            || pathname === "index.html" || pathname === "home.html") {
        // If it should be routed to the home page.
        path += "index.html"; // Sets it to the index page
        corrected = true;

    } else {

        // If it isn't any of those, then just appends the pathname
        path += pathname;
    }

    // Splits it using "." seperator. If the lenght of the split is only one
    // then no file type has been specified, and so one will be generated
    var pathSplit = pathname.split(".");

    if (pathSplit.length === 1 && corrected === false) {
        // If the split leaves length one then appends .html to the end.
        path += ".html";

    }
    console.log("Path is : " + path);
    return path; // Returns the path.

};

exports.route = route;

pageserver.js

var path = require("path");
var fs = require("fs");

// Serves the page by returning the html.
var serve = function(path) {

    var html = "";

    try {
        html = fs.readFileSync(path);
    } catch (err) {
        console.log("Reading file was unsuccesful.");
        html = "ERROR";
    }

    return html;
};

// returns the type of file aka filename extension
var reqtype = function(path) {

    var type = "";

    var pathSplit = path.split(".");
    if (pathSplit === 1) {
        // If for somereason no ending, output as plain text file
        type = "plain";
    } else {

        type = pathSplit[1]; // Returns thee part after the "." seperator
    }

    return type;
};

exports.serve = serve;
exports.reqtype = reqtype;

Please let me know if the code seems to be glitchy. Shouldn't be though.

Thanks SbSpider

share|improve this answer
 
If you think this is a bad answer worthy of a downvote, then please at least tell me what is wrong with it. I mean, I provided documented code for what the OP asked for, and it answered his question I think well - it is a web server made from node that serves js and css pages as well (js just needs a small change to the code, but otherwise is easy). –  Sbspider Nov 9 at 3:11
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.