Search code examples
javascripthtmlnode.jsmime-typesnodejs-server

How to set the Content-Type of a Js-File in NodeJS-App


i have a problem opening a js-file on my NodeJS-server, because it will always specify my .js-file with a Content-Type of "text/html".

The goal is to send user-input from a html-form to a JavaScript-file for doing some calculations and later create a Graphic from it.

On my app.js (Node-Server) i have:

const http = require('http');
const fs = require('fs');
const port = 3000;
const server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' })
fs.readFile('index.html', function(error, data) {
        if (error) {
            res.writeHead(404)
            res.write('Error: File Not Found')
        } else {
            res.write(data)
        }
        res.end()
    })
})

This will open my html-file correctly. Which is an input-form like follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="module" src="./js/index.js"></script> 
    <title>Node-App</title>
</head>
<body>
    Enter Name and Birthdate:<br><br>
    <form action="#" method="post" id="frm">
        <label for="Name">Name:</label><br>
        <input type="text" id="nam"><br>

        <label for="Date">Date:</label><br> 
        <input type="text" id="dat"><br>

        <input type="button" onclick="userInput()" value="Plot">
    </form>

But now i want to open a js-function from here by clicking a button, which gives me the error "userInput is not defnied".
Not a surprise, since loading the page already throw the error "Loading the Module from "www/js/index.js" was blocked by a disabled MIME-Type (text/html)"

My JS-file looks like this, but is not loaded correctly anyways:

function userInput() {
    console.log("Test The Function");
}

I can see in "Network Analysis", in the .js-files's http-header, that its Content-Type is "text/html", so my question is how can i change this?

I tried several things already like setting it in my app.js by typing res.writeHead(200, { 'Content-Type': ['text/html', application/javascript] }) or res.setHeader("Content-Type": "application/javascript"); but it would either not load the html anymore or just do nothing.

Also i tried to set the Content-Type in my index.html as a script-tag like <script type="application/javascript" src="./js/index.js"></script> , but it also changes nothing.

Thanks for your help!


Solution

  • By default when you serve an html page to the browser, it will analyze your document and if it finds links to css or javascript, it will make an HTTP request to the server that holds these assets.

    When you open the browser console via the devTools, you may notice that you either have an error message telling you that it was not possible to GET the requested resource (the name of your javascript file), or your page loads infinitely without returning a response.

    So from that we can understand a very simple thing, it's that you have to manage the routes to the resources stored in your server.

    For example, the browser will query your server with a GET method and the url http://localhost:3000/script.js, after which your server must serve it this asset.

    Here's an example to illustrate this:

    Imagine a file structure containing:

    • a public folder, which itself contains an 'assets' folder and an 'html' folder.

    • a server.js file containing your server logic.

    This html folder would contain the html file to serve.

    The assets folder would contain the 'script.js' and 'styles.css' files.

    "use strict";
    
    const http = require("http");
    const fs = require("fs");
    const os = require("os");
    const path = require("path");
    
    const host = "localhost";
    const port = 3000;
    
    const server = http.createServer((req, res) => {
        if (req.method === "GET") {
            if (req.url === "/") {
                const readStream = fs.createReadStream(path.join(process.cwd(), "public", "html", "index.html"));
                res.writeHead(200, {
                    "Content-Type": "text/html",
                });
                readStream.pipe(res);
            }
            if (req.url === "/styles.css") {
                const readStream = fs.createReadStream(path.join(process.cwd(), "public", "assets", "styles.css"));
                res.writeHead(200, {
                    "Content-Type": "text/css",
                });
                readStream.pipe(res);
            }
            if (req.url === "/script.js") {
                const readStream = fs.createReadStream(path.join(process.cwd(), "public", "assets", "script.js"));
                res.writeHead(200, {
                    "Content-Type": "text/html",
                });
                readStream.pipe(res);
            }
        }
    
    });
    
    server.on("listening", () => {
        console.log(`Server running on http://${host}:${port}`);
    })
    
    server.listen(port);
    
    process.on("SIGINT", () => {
        console.log(`${os.EOL}Server interrupted by 'SIGINT'`);
        process.exit(1);
    });
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Node-App</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        Enter Name and Birthdate:<br><br>
        <form action="#" method="post" id="frm">
            <label for="Name">Name:</label><br>
            <input type="text" id="nam"><br>
    
            <label for="Date">Date:</label><br> 
            <input type="text" id="dat"><br>
    
            <input type="button" onclick="userInput()" value="Plot">
        </form>
        <script src="script.js"></script>
    </body>

    In this example I'm using createReadStream() from the 'fs' module for a performance boost, which I strongly advise you to use when serving static files.

    Now when the browser will make one or more requests to your server, concerning assets such as 'script.js' or 'styles.css' as in my example, your server will serve it the requested files.

    Hope this helps, good luck!