Node.js: My HTML requires an image - html

See, I was training with Node (and TS btw), and tried to do a trivial server with multiple request/response options. But I have a problem I don't know how to solve without using Express (at least for now I don't want to use it).
I have a HTML file which requests an image file. While in the IDE, everything looks like it's going to work, but when the server is running, the image cannot be found. It's kind of obvious why: The HTML makes a request the server doesn't know how to handle. Thing is, I thought the document could refer to other files without the need of talking to the server.
What is an elegant and working solution for my problem?
Thanks in advance.
import * as http from 'http'
import * as fs from 'fs'
fs.readFile('doc/kmCNHkq.jpg', function (err, data) {
let binaryimg = new Buffer(data).toString('base64');
if (err) throw err;
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'image/jpeg'});
res.end(data);
console.log("Delivered the jpeg");
}).listen(8000);
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(binaryimg);
console.log("Delivered base64 string");
}).listen(8124);
console.log("Unless bug, both servers are listening");
});
fs.readFile('doc/index.html', function(err, data) {
http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data)
}).listen(80);
console.log("HTML server is running")
})
(main.ts; Targets ES6)
<html>
<head>
</head>
<body>
<img src="doc/kmCNHkq.jpg"/>
</body>
</html>
(index.html)
Observation: I used to leave the HTML file in '../doc/' and resources on '../img/' however it seems that the HTML uses relative paths, so I copied the image into HTML's folder. If the solution also made it so I could leave the resources on their's respective folders it would be much appreciated.
#Edit:
Now I'm using this switch/case request handler. Working as expected, the HTML's request for the image is interpreted as a normal request (which may not end up scaling well, idk, but screw it). Thanks a lot!
import * as http from 'http'
import * as fs from 'fs'
var stream: fs.ReadStream,
folder = __dirname.substr(0, __dirname.length - 3);
http.createServer(function(req,res) {
switch (req.url){
case('/jpeg'):
stream = fs.createReadStream(folder + 'img/kmCNHkq.jpg');
stream.pipe(res);
console.log("Delivering the jpeg");
break;
case('/base64'):
fs.readFile('img/kmCNHkq.jpg', function (err, data) {
let img64 = new Buffer(data).toString('base64');
if (err) throw err;
res.end(img64);
console.log("Delivered base64 string");
})
break;
case('/html'):
stream = fs.createReadStream(folder + 'doc/index.html');
stream.pipe(res);
console.log("Sending the docs");
break;
default:
console.log("Shit happens");
}
}).listen(80)
(main.ts)
<html>
<body>
<img src="jpeg"/>
</body>
</html>
(index.html)

Short answer:
You won't be able to refer to specific resources on the server (such as your image) unless your server knows how to respond to those requests for that content. It looks like you can probably make your example work easily immediately though by changing the image src to just http://localhost:8000 though.
Longer answer:
Using 'doc/kmCNHkq.jpg' as the src for your image tells your browser that when it loads the page, it should go to the server it got the page from, and ask it for the 'doc/kmCNHkq.jpg' resource. If you specify a full URL including the protocol (the http://) then it will be absolute, instead of relative, so you can request from a different server than the one that served the page.
The servers that you've written don't actually look at the path of the file that's requested though (req.url), and actually they just always return the same content. If you connect to http://localhost:80 (the third server you've created above), and do request that jpg you'll still just get given the same HTML data of the page, because it just runs the two lines in your createServer call at the end of your example. You have written a server that always returns the image however above (the first server), just running on a different port, which is why the above solution works.
Just using that existing server is the simplest solution. The far more conventional approach though is to have just a single HTTP server running on a single port (instead of the 3 you have) and to use req.url to decide what data to return.
Traditionally for static content that means mapping a requested path directly onto the layout of the files on disk, so that requesting doc/abc.jpg looks for a doc folder in the server's directory, and returns the data from abc.jpg therein. That's not required necessarily at all though, and your server can interpret those paths however you like, to return content from anywhere.
(Note than none of this is really anything to do with TypeScript, or even much to do with Node.js. This is really just the essentials of how HTTP servers and browsers interact, and it would be almost identical with any other backing technology. I'd take a look more into the general HTTP and browser details if you're looking to get more background on this.)

Related

Redirect in express

I am using express and I would like to redirect to another file since my server is not always up and running. I can not understand why I am receiving a HTML document when my file is JSON. It looks like it gets redirected, but the result is wrong. I can see that my page is redirected from the old URL to the new URL. So it looks like that part is working. But I am not receiving my local json-file in the response.
What I have in my server index.js file:
app.use('/my/original/url', (req, res) => {
res.writeHead(302, { location: '/mock/mockedresult.json' });
res.end();
});
I found out that I need to make my mock folder available. I did so by adding this line of code above the code snippet in my question:
app.use('/mock', express.static(resolve(process.cwd(), 'server/mock')));

Create Action For Running Nodejs inside HTML

I am new at Node.js
I create a server with node.js I have file like this:
Server.js
Client.js
Index.html
Server configuration is okay. But Inside HTML, I would like to link or an action to run client.js
At HTML, usually we use Link to link a page.
or
run npm with node client.js to run client.js
How I do it at html to run client.js, so if we click a link - client.js will run (the action is same like we do for run at npm node client.js)?
EDIT :
Oke, it looks like difficult to run client.js inside html with click. I changed my question.
I run node.js. And I open a browser (with anything extension html or js) and I would like to run client.js with a click. How do I do that?
I have never hear of such thing.
But I think, if you want to change something in server through frontend, http ajax is a good way.
But according to my acquaintance, when server accept a request from frontend, in a general way,it will run some code,such as function, but not js file.
You could run js file through child_process, it is a module in node, which use to call the shell in your system.
PS, shell.js is a better way if you want to call the shell in nodejs.
see this. https://github.com/shelljs/shelljs
Some server side programming environments work on the basis of having a program, in a file, for each URL that needs to be handled.
Node.js does not work that way.
You write a single server program which handles all the requests and which examines the URL of each one to determine what to do.
const http = require('http');
const server = http.createServer((req, res) => {
console.log(req.url);
if (req.url == "/") {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("The homepage");
} else if (req.url == "/client.js") {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("Whatever you want to do for a request for client.js");
} else {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end("Not found");
}
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
While you might store some code in client.js, that filename wouldn't be mentioned to the client. The server would just load it like any other module and then conditionally call functions from it.

Removing case sensitivity Node subfolder

I have a Linux webserver using node which hosts a directory containing a static index.html file. I am wondering how I can make it so a user getting to the correct URL does not rely upon case sensitivity.
Currently, server.com/caa/ points to something different than server.com/CAA/ -- the directory holding index.html is lowercase "caa"
Have you tried adding some middleware that coverts all urls to lower case? Heres an example of one way of doing this
app.use(function(req, res, next) {
req.url = req.url.toLowerCase();
next()
});

Node js - socket.io - Linked Stylesheet not loading... port issue?

I have a working chat application ( tutorial here : https://www.youtube.com/watch?v=QISU14OrRbI ) hooked to mysql instead of mongodb.
All of my code in a paste, minus the css : http://pastebin.com/j5FLZyFP
I have always been able to link to a css file via the link element in the DOM head. I am wondering why this approach doesn't work in my example and if it has anything to do with which ports i am using. The server that serves the index.html page is running on port 8080, while my sockets server is running on port 9000. Should I be using the same port for both of them? If so, how do I do that?
Below are screenshots of my browser # 127.0.0.1:8080
I need 10 reputation to post more than 2 links, slap my wrist I suppose - https[colon][slash][slash]imgur[dot]com[slash]a[slash]22Vv5
I get served the page, but i am forced to press ESC to stop the main.css from getting transferred. Then the remaining requests come through. don't be concerned about inject.js, it represents the Wappalyzer extension and I have tried the example with Wappalyzer disabled.
Adding my CSS to a style tag works and isn't too much trouble to implement in my case, but it would be nice to solve this problem. Thanks.
Kamran Adil in the comments has answered this well. See linked question: Node.js - external JS and CSS files (just using node.js not express)
this worked just fine adding a new condition to test the request
var param = 'main'; /* Stylesheet file name */
if(req.url.indexOf('.css') != -1) {
fs.readFile('./styles/'+ param +'.css', function (err, data) {
if (err) { console.log(err); }
res.writeHead(200, {'Content-Type': 'text/css'});
res.write(data);
res.end();
});
}

Custom 404 error without server

Is possible to intercept 404 error without using web server (browsing html file in the filesystem) ?
I tried with some javascript, using an hidden iframe that preload the destination page and check for the result and then trigger a custom error or redirect to the correct page.
This work fine but is not good on perfomance.
A 404 error is an HTTP status response. So unless you are trying to retrieve this file using an HTTP request/response, you can't have a genuine 404 error. You can only mimic one in something like the way you suggest. Any "standard" way of handling a 404 error is dependent on your flavour of web server anyway...
404 is a HTTP response code, and as such only delivered through the HTTP protocol by servers that speak it. The file:// extension isn't a real protocol response as such, it's a hack built into clients (like browsers) that enable local file support, however it's up to browsers / clients themselves whether they expose any response codes from their file:// implementation. In theory they could report them in the DOM, for example, but they would be response codes exposed to themselves, and as such rarely implemented. Most don't, and there isn't a standard way for it. You may look into browser extensions, like Firefox, and see if they support it, but then, this is highly unstandard and will likely break if you pop it on the web.
Why don't you want to use the server?
I don't believe that it's possible to handle a 404 error client-side, because a 404 error is server-side.
Whenever you load a webpage, you make a request to the server. Thus, when you ask for a file that's not there, it's the server that handles the error. Regular HTML/CSS/JavaScript only come into the picture when the server sends back a response to tell you that it can't find the file.
Steve
Because I was looking for this today. You can now do this without a server by using a Service Worker to cache the custom 404 page, and then serve it when a fetch request status is 404. Following the instructions on the google cache lab, the worker files looks as follows:
const filesToCache = [
'/',
'404.html'
];
const staticCacheName = 'pages-cache-v1';
self.addEventListener('install', event => {
console.log('Attempting to install service worker and cache static assets');
event.waitUntil(
caches.open(staticCacheName).then(cache => {
return cache.addAll(filesToCache);
});
);
});
self.addEventListener('fetch', event => {
console.log('Fetch event for ', event.request.url);
event.respondWith(
caches.match(event.request).then(response => {
if (response) {
console.log('Found ', event.request.url, ' in cache');
return response;
}
console.log('Network request for ', event.request.url);
return fetch(event.request).then(response => {
console.log('response.status:', response.status);
// fetch request returned 404, serve custom 404 page
if (response.status === 404) {
return caches.match('404.html');
}
});
});
);
});