I'm a Node.js newb, so I'm not sure if it's possible to do what I'm trying to accomplish. Here is my configuration:
I have a Node.js server running on a Raspberry Pi on my home network. I have an HTML file on an external IP. I wish to render React components on this HTML file.
From what I've seen, people have used Node servers to display js on a local HTML file, so the path would normally look like this, assuming the directory is called 'dir':
const express = require('express');
const app = express();
// Static Routes
app.use('/dist', express.static(path.join(__dirname, 'dir')));
// App Route
app.get('/', (req, res, next) => res.sendFile(path.join(__dirname,
'index.html')));
Which, to my knowledge, transfers the HTML file found at the previously specified path. But where is this transferred to? Any way I can specify the path name based on an external IP + user + password, and file path?
Which, to my knowledge, transfers the HTML file found at the previously specified path. But where is this transferred to?
It transfers the file contents from disk to the client's network connection, when they request it (i.e. not when the server starts up).
Any way I can specify the path name based on an external IP + user + password, and file path?
Not with express.static. If you want to make your server serve an external page (proxying), you can do that: https://stackoverflow.com/a/10435819/7011366. Since you'll have access to the url & cookies, you can do whatever you like with the path/user/password.
app.post('/my_url', function(req, res) {
var options = {
host: MY_DOMAIN,
path: '/' + req.query.username,
method: 'GET',
};
var req = http.request(options, function(res) {
// etc...
// send response to client
}).on('error', function(e) {
// handle error...
}).end();
});
This above example makes a request to the external page every on every request. If you don't want that, you can store it in memory and only update it periodically.
let myHtml = "";
let fn = () => {
var options = {
host: MY_DOMAIN,
path: '/' + req.query.username,
method: 'GET',
};
var req = http.request(options, function(res) {
// etc...
// save response to myHtml as string
}).on('error', function(e) {
// handle error...
}).end();
};
setInterval(fn, 60000);
fn();
app.post('/my_url', function(req, res) {
res.end(myHtml);
});
You can not achieve it directly for the files stored on remote machine. Express static path works with local file system only.
Possible way for this could be, fetch file from the remote machine every time you get a new request. But no one does this.
Related
This question already has answers here:
How to download multiple files with one HTTP request?
(5 answers)
Closed 9 months ago.
I'm new to anything web-development related (I've only been coding using luau for about a year now), and I'm having trouble sending multiple files when my server gets pinged, because I want to have a separate style.css file, as well as different script things.
I've left out MouseDraw.js and style.css, but when I added them directly into index.html they worked, and I can't see them when I inspect element on the website so I think it's just that they aren't being sent.
Is it possible to send them or do I have to just put them in every file?
I would post an image of how it's structured but I'm new so I can't, but it's all under a folder, and then there's just 'Server.js' and a folder called Client, which has everything I want to send to the client.
Server code:
const http = require('http');
const fs = require('fs').promises
const hostname = 'localhost';
const port = 8000;
let loadedPageInfo;
fs.readFile(__dirname + "/Client/index.html") // Get and read the HTML data for this page
.then((contents) => {
loadedPageInfo = contents
})
.catch((error) => {
console.log(`Could not load index.html ${error}`)
})
const server = http.createServer((req, res) => {
res.end(loadedPageInfo || "Error loading");
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Client:
index.html:
<head>
<title>Drawing</title>
<link rel = "stylsheet" type = "text/css" href = "style.css">
</head>
<body>
<h1>Heading One</h1>
<p1>Message from my computer:</p1>
<p2><samp><br><br>File not found.<br>Press F1 to do nothing</samp></p2>
</body>
<script> src = "MouseDraw.js" </script>
</html>
style.css will be requested as a new http request from the browser. It will be asking for /style.css. Your http server just sends loadedPageInfo no matter what the incoming request path is, so when the browser asks for /style.css, your http server just sends it loadedPageInfo. The browser will probably see that it's an incorrect file type (e.g. not a CSS file) and will end up ignoring it.
Same thing would happen for MouseDraw.js. If you want the browser to be able to get /style.css and /MouseDraw.js, then you will need to check for those in your http server and send the right file that matches the request.
In the Express framework, you can configure express.static() to automatically serve a bunch of static HTML files like these, but without that, you have to literally write code for each separate http request that you want to serve, checking the incoming path of the request and sending the file that matches that request.
I'd really recommend using the very lightweight Express web server framework as it makes all of this simpler without getting in your way. But here's the general idea for coding it manually:
function sendFile(res, file) {
const filename = path.join(__dirname, "/Client", file);
fs.readFile(filename).then(data => {
res.end(data);
}).catch(err => {
console.log(err);
res.statusCode = 404;
res.end();
});
}
const server = http.createServer((req, res) => {
switch(req.url) {
case "/":
sendFile(res, "index.html");
break;
case "/style.css":
sendFile(res, "style.css");
break;
case "/MouseDraw.js":
sendFile(res, "MouseDraw.js");
break;
default:
res.statusCode = 404;
res.end();
break;
}
});
I am unable to successfully send a SQL query from a served javascript file back to the server so that the server can process it. I intend on sending the result back to the javascript to do some conditional graphics work with p5.js. There will only ever be one user connected to the server at a time (me)
I am very in the dark when it comes to server structure and web development so I haven't even known where to start. Any chances at research have been shot down by a lack of results. I really just need the ability to store things to a database and query with SQL and do graphics work based on the result of the queries. As such I have tried moving to processing-java but the only library that allows for DB communication with SQL is horribly out of date and does not work with the current version of MySQL.
The actual server code is as follows:
const http = require('http');
const path = require('path');
const fs = require('fs');
const mysql = require('mysql');
let connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "root"
});
function handleRequest(req, res) {
console.log(req.url);
let pathname = req.url;
if (pathname == '/') {
pathname = '/index.html';
}
let ext = path.extname(pathname);
const typeExt = {
'.html': 'text/html',
'.js': 'text/javascript',
};
let contentType = typeExt[ext] || 'text/plain';
fs.readFile(__dirname + pathname,
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading ' + pathname);
}
res.writeHead(200,{ 'Content-Type': contentType });
res.end(data);
}
);
}
let server = http.createServer(handleRequest);
server.listen(8080);
console.log('Server started on port 8080');
and it serves a p5 javascript sketch and an html file.
The current script can connect to the MySQL server I have running, and can serve the p5 script properly but I can't get the connection between them. Any help would be greatly appreciated.
I would like to use the output of my nodeJS. This is my code
var fs = require('fs'); //File System
var rutaImagen = 'C:/Users/smontesc/Desktop/imagenes1/'; //Location of images
fs.readdir(rutaImagen, function(err, files) {
if (err) { throw err; }
var imageFile = getNewestFile(files, rutaImagen);
//process imageFile here or pass it to a function...
console.log(imageFile);
});
function getNewestFile(files, path) {
var out = [];
files.forEach(function(file) {
var stats = fs.statSync(path + "/" +file);
if(stats.isFile()) {
out.push({"file":file, "mtime": stats.mtime.getTime()});
}
});
out.sort(function(a,b) {
return b.mtime - a.mtime;
})
return (out.length>0) ? out[0].file : "";
}
And the result is console.log(imageFile), I want to call the result of this in my javascript project, like
<script>
document.write(imageFile)
</script>
All this is to get the newest file created in a directory because I can't do it directly on JS.
Thanks a lot
First, there are several fundamental things about how the client/server relationship of the browser and a web server work that we need to establish. That will then offer a framework for discussing solving your problem.
Images are displayed in a browser, not with document.write(), but by inserting an image tag in your document that points to the URL of a specific image.
For a web page to get some result from the server, it has to either have that result embedded in the web page when the web page was originally fetched from the server or the Javascript in the web page has to request information from the server with an Ajax request. An ajax request is an http request where the Javascript in your web page, forms an http request that is sent to your server, your server receives that request and sends back a response which the Javascript in your web page receives and can then do something with.
To implement something where your web page requests some data from your back-end, you will have to have a web server in your back-end that can response to Ajax requests sent from the web page. You cannot just run a script on your server and magically modify a web page displayed in a browser. Without the type of structure described in the previous points, your web page has no connection at all to the displayed server. The web page can't directly reach your server file system and the server can't directly touch the displayed web page.
There are a number of possible schemes for implementing this type of connection. What I would think would work best would be to define an image URL that, when requested by any browser, it returns an image for the newest image in your particular directory on your server. Then, you would just embed that particular URL in your web page and anytime that image was refreshed or displayed, your server would send it the newest version of that image. Your server probably also needs to make sure that the browser does not cache that URL by setting appropriate cache headers so that it won't mistakenly just display the previously cached version of that image.
The web page could look like this:
<img src='http://mycustomdomain.com/dimages/newest'>
Then, you'd set up a web server at mycustomdomain.com that is publicly accessible (from the open internet - you choose your own domain obviously) that has access to the desired images and you'd create a route on that web server that answers to the /dimages/newest request.
Using Express as your web server framework, this could look like this:
const app = require('express')();
const fs = require('fs');
const util = require('util');
const readdir = util.promisify(fs.readdir);
const stat = util.promisify(fs.stat);
// middleware to use in some routes that you don't want any caching on
function nocache(req, res, next) {
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate, proxy-revalidate');
res.header('Expires', '-1');
res.header('Pragma', 'no-cache');
next();
}
const rutaImagen = 'C:/Users/smontesc/Desktop/imagenes1/'; //Location of images
// function to find newest image
// returns promise that resolves with the full path of the image
// or rejects with an error
async function getNewestImage(root) {
let files = await readdir(root);
let results = [];
for (f of files) {
const fullPath = root + "/" + f;
const stats = await stat(fullPath);
if (stats.isFile()) {
results.push({file: fullPath, mtime: stats.mtime.getTime()});
}
}
results.sort(function(a,b) {
return b.mtime - a.mtime;
});
return (results.length > 0) ? results[0].file : "";
}
// route for fetching that image
app.get(nocache, '/dimages/newest', function(req, res) {
getNewestImage(rutaImagen).then(img => {
res.sendFile(img, {cacheControl: false});
}).catch(err => {
console.log('getNewestImage() error', err);
res.sendStatus(500);
});
});
// start your web server
app.listen(80);
To be able to use that result in your Javascipt project, we definitely have to create an API which has a particular route that responses the imageFile. Then, in your Javascript project, you can use XMLHttpRequest (XHR) objects or the Fetch API to interact with servers to get the result.
The core idea is we definitely need both server-side and client-side programming to perform that functionality.
I want to create a server-side app using node.js with express. At the moment I am able to get the json document with the location and temperature but after I used pykite to get it online the application would only get the server location to the one who is accessing it. Here is the code in its current form:
var express = require('express');
var app = express();
var request = require('request');
app.get('/api/weather/current_temperature', function (req, res) {
request('http://api.wunderground.com/api/ebb3e0cf5059cce8/conditions/q/autoip.json', function(error, response, body){
if (!error && response.statusCode==200){
res.setHeader('Content-Type', 'aplication/json');
var result = JSON.parse(body);
res.json({ "location": result.current_observation.observation_location.city,"temperature": result.current_observation.temp_c });
}else{
console.log(error, response.statusCode, body);
}
res.end("")
});
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('The app is up.');
});
I admit I'm new to this but I wanna learn. I would like some help implementing it in this code, if it's possible, a way to access the user's location and determine the weather at his/her location.
Thank you in advance.
P.S.: I would also like some links into some documentation, don't wanna skip anything.
The URL you are linking to http://api.wunderground.com/api/YOUR_KEY/conditions/q/autoip.json (which doesn't work because you didn't provide your key) has autoip in the name.
That implies that it will return a result from whatever IP address the request came from.
So you have two options:
Don't make the request from NodeJS. Make the request from the browser. (This probably isn't advisable given the use of an API key and might run into Same Origin Policy issues).
Find a different API (possibly one from the same site) that lets you specify what IP address or location to use.
Sorry, I tend to be a bad writer when I have not fully woken up, let me revise.
I am using expressjs with passportjs (local strategy) to manage my server and using connect-busboy to manage file uploading. I do not think passport will play a role in this.
Here is the server code for managing file uploads:
app.post('/upload', isLoggedIn, (req, res) => {
if(req.busboy){
req.pipe(req.busboy);
req.busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
if(mimetype.match(/^image\//)){
var root = path.join(__dirname, "../public/images/");
if(fs.existsSync(path.join(root, filename))){
var name = getUnique(path.join(root, filename));
} else {
var name = filename;
}
var ws = fs.createWriteStream(path.join(root, name), { flags: "a" });
file.pipe(ws);
}
});
}
});
As for my client page, it is used to change a JSON object which will get re-uploaded to the server as a configuration tool. When I upload a new image asynchronously I need to get the filename to update this JSON object while working on it. For uploading from the clients end I am using dropzonejs, which did not require any configuration on my part to work.
So, in summary I upload a number of images via dropzone asynchronously, busboy and fs on my server save the file, and I would like to get the filename returned to my javascript to modify the existing JSON object.
Edit solution:
Thanks to Elliot Blackburn for pointing me in the right direction.
By calling:
ws.on('close', () => {
res.send({filename: name});
});
after file.pipe(ws); to send the response back to the client. On the client side modify dropzone to handle the response like so:
dropzone.on('success', (file, res) => {
console.log(res);
});
Just send it in the normal http response. It'll depend what library you're using but most will allow you to trigger a normal req, res, next express call. From that you can access the file object, and return anything you want.
Something like:
req.send({filename: name}); // name is the filename var set earlier in the code.
Once you've finished editing the file and such, you can get the name and put it into that returned object and your client will receive that as object as the response which you can act upon.