0

I am not able to use more HTML files. I want to add 2-3 HTML links in my index.html, how can I do it? Below is my code where I used 2 html pagelinks, one css and one js.

This is test.js file:

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

http.createServer(function (req, res) {

    if(req.url.indexOf('.html') != -1){ //req.url has the pathname, check if it conatins '.html'

      fs.readFile(__dirname + '/public/index.html', function (err, data) {
        if (err) console.log(err);
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write(data);
        res.end();
      });

    }

    if(req.url.indexOf('.js') != -1){ //req.url has the pathname, check if it conatins '.js'

      fs.readFile(__dirname + '/public/js/bootstrap.min.js', function (err, data) {
        if (err) console.log(err);
        res.writeHead(200, {'Content-Type': 'text/javascript'});
        res.write(data);
        res.end();
      });

    }


    if(req.url.indexOf('.css') != -1){ //req.url has the pathname, check if it conatins '.css'

      fs.readFile(__dirname + '/public/css/bootstrap.min.css', function (err, data) {
        if (err) console.log(err);
        res.writeHead(200, {'Content-Type': 'text/css'});
        res.write(data);
        res.end();
      });

    }
    if(req.url.indexOf('.html') != -1){ //req.url has the pathname, check if it conatins '.js'

      fs.readFile(__dirname + '/public/hello.html', function (err, data) {
        if (err) console.log(err);
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write(data);
        res.end();
      });

    }

}).listen(3000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3000/');

I got this error in cmd while loading server:

D:\Nodejs>node test.js
Server running at http://127.0.0.1:3000/
events.js:160
      throw er; // Unhandled 'error' event
      ^

Error: write after end
    at ServerResponse.OutgoingMessage.write (_http_outgoing.js:441:15)
    at D:\Nodejs\test.js:45:13
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:446:3)
FirstOne
  • 6,033
  • 7
  • 26
  • 45

2 Answers2

3

It seems that you are trying to write your own static file server in Node. There are easy solution for that, like the express.static middleware in the Express framework, where all you do is something like this:

Ready solution

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

var dir = path.join(__dirname, 'public');

app.use(express.static(dir));

app.listen(3000, () => console.log('Listening on http://localhost:3000/'));

(this is the entire program).

Reinventing the wheel

Now, if you insist of reimplementing all of that yourself then read on.

One of the bugs in your code is checking for the extensions when you in fact check for having strings like .html anywhere in the code. E.g. this:

if(req.url.indexOf('.html') != -1)

will match files like /my.html.styles/style.css which it shouldn't. If you want to check the file extension then use:

path.extname(file);

See: https://nodejs.org/api/path.html

Also it doesn't terminate when it finds a match because you're using plain if and not else if blocks and you don't use early return in your code.

Another problem is that you have hardcoded all of the paths to files and with that code you will not be able to serve just any HTML or CSS code. Also your code will not serve images correctly, or multiple styles etc. It would actually be easier to rewrite from scratch that try to fix it.

Good examples

See this answer for examples of how to properly serve static images with Express andexpress.static, Express without express.static, connect, http module (like you do here) and net module with raw TCP connections:

Here is a full example of a file server using only http i.e. what you're trying to do here:

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

var dir = path.join(__dirname, 'public');

var mime = {
    html: 'text/html',
    txt: 'text/plain',
    css: 'text/css',
    gif: 'image/gif',
    jpg: 'image/jpeg',
    png: 'image/png',
    svg: 'image/svg+xml',
    js: 'application/javascript'
};

var server = http.createServer((req, res) => {
    var reqpath = req.url.toString().split('?')[0];
    if (req.method !== 'GET') {
        res.statusCode = 501;
        res.setHeader('Content-Type', 'text/plain');
        return res.end('Method not implemented');
    }
    var file = path.join(dir, reqpath.replace(/\/$/, '/index.html'));
    if (file.indexOf(dir + path.sep) !== 0) {
        res.statusCode = 403;
        res.setHeader('Content-Type', 'text/plain');
        return res.end('Forbidden');
    }
    var type = mime[path.extname(file).slice(1)] || 'text/plain';
    var s = fs.createReadStream(file);
    s.on('open', () => {
        res.setHeader('Content-Type', type);
        s.pipe(res);
    });
    s.on('error', () => {
        res.setHeader('Content-Type', 'text/plain');
        res.statusCode = 404;
        res.end('Not found');
    });
});

server.listen(3000, () => console.log('Listening on http://localhost:3000/'));

This code is much more complicated and doesn't even serve properly files with other MIME types than the ones explicitly supported, which only demonstrates that it's much better to use module that does all of that properly.

So preferably use the right tool for the job, like express.static or any other well tested Node static file server and you will avoid a lot of the problems.

For more info see:

Community
  • 1
  • 1
rsp
  • 107,747
  • 29
  • 201
  • 177
-1

This is caused by your if statement. You should be using something like this:

if(req.url == '/index.html'){
    // load index.html
}else if(req.url == '/hello.html'){
    // load hello.html
}else if ... // the rest for css and js


Some explanations
  • When you check just the indexOf of the request url, you won't be able to differ index.html from hello.html (both have .html), so what you want to check is the file itself.

  • For that error, since any .html in the url matches both IFs, and you are not using if..else, it will enter both, calling end in the request in one IF, and trying to write after end in the other.


Side note

This should be used only for learning purposes. There is no need to use this method once you get a grasp on how it works and what's happening, because, when you do, just go with well-known tools that do the job in much simpler ways.

FirstOne
  • 6,033
  • 7
  • 26
  • 45
  • Are you seriously suggesting to hardcode the path of every file on the server in the request handler with a giant if/else? I mean seriously, what if there are 20,000 files and they keep changing? – rsp Apr 17 '17 at 10:55
  • I'm assuming the OP is learning, judging by the simplicity of code. And sometimes it's important that poeple learn _how stuff works_ before using tools and libraries that do it for them like suggested. It seemed to me they just tried to edit an example / tutorial to mess with the code and make some tests to see it working, not really publish the company's website @rsp – FirstOne Apr 17 '17 at 11:05