xzela
xzela

Reputation: 43

Simple Nodejs web server always sends text/plain css and js files

I'm running into a weird problem when creating a simple web server in Nodejs. The http server runs fine and accepts requests and responses like it should. However, for some reason it always wants to send a content-type: of text/plain for everything. For example, .js and .css files always come down as text/plain whereas they should normally be sent as text/css or application/javascript. Chrome, the browser I'm using to test this, always complains about the MIME type of the resource:

Resource interpreted as Stylesheet but transferred with MIME type text/plain: "http://localhost:3000/test.css".

Resource interpreted as Script but transferred with MIME type text/plain: "http://localhost:3000/test-client.js".

What this ultimately means is the css is never applied to the page. I've added some logging and it appears that the http response is sending down the correct MIME type.

I've created a barebones version of what I'm doing. Hopefully someone can point out the flaw that I've coded:

test.js

var http = require('http'),
    fs = require('fs'),
    url = require('url'),
    path = require('path');
var contentTypes = {
    '.html': 'text/html',
    '.css': "text/css",
    '.js': 'application/javascript'
};
http.createServer(function(request, response) {
    // get file based on pathname
    var uri = url.parse(request.url).pathname,
        filename = path.join(__dirname, uri);
    fs.exists(filename, function(exists) {
        // if root directory, append test.html
        if (fs.statSync(filename).isDirectory()) {
            filename += 'test.html';
        }
        // figure out MIME type by file ext
        var contentType = contentTypes[path.extname(filename)];
        fs.readFile(filename, function(err, file) {
            // errors?
            if (err) {
                response.writeHead(404, {'Content-type:': 'text/plain'});
                response.write(err + "\n");
                response.end();
            } else {
                console.log('MIME TYPE for: ', filename , contentType);
                response.setHeader('Content-Type:', contentType);
                response.writeHead(200);
                response.write(file);
                response.end();
            }
        });
    });
}).listen(3000, function(){
    console.log("server started and listening on port 3000");
});

test.html

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="test.css" type="text/css" />
    </head>
    <body>
        <h1>Test</h1>
        <div id="test"></div>
        <script type="text/javascript" src="test-client.js"></script>
    </body>
</html>

test.css

h1 {
    color: red;
}

test-client.js

var div = document.getElementById('test');
div.innerHTML = 'test client ran successfully';

Upvotes: 4

Views: 4437

Answers (3)

Rens
Rens

Reputation: 745

I ran into the same problem, however mine was caused slightly differently. I was initially using this method to set the Content_Type:

res.writeHead(200, { 'Content_Type': contentType });

After replacing it with the following the errors disappeared:

res.setHeader('Content-Type',contentType)

Upvotes: 0

liuchzong_legend80s
liuchzong_legend80s

Reputation: 1

And you must made fs.readFile wrapped by a closure, otherwise some file (especially the last file) will be read more than once, and others will not be read at all. And the contentTypewill not be set as you wish. This is because of the callback strategy used by fs.readFile. The problem does not appear when the html file just load one external file, but as the external files(css, js, png) loaded more than one it will appear as i pointed out above. (I cannot login with my gmail so I post as a guest)

So your code should make a little change as follows:

;(function (filename, contentType) {

    fs.readFile(filename, function(err, file) {
        // do the left stuff here
    });

}(filename, contentType)); 

Upvotes: 0

markasoftware
markasoftware

Reputation: 12662

I think the issue is that you are using an unnecessary : after Content-Type when setting headers. You should either do response.setHeader('Content-Type',contentType); or, which I think is even better, do this: response.writeHead(200,{'Content-Type':contentType});

Upvotes: 4

Related Questions