I'm running a program that validates a .html file (index.html) and then runs the program on a web-browser. (localhost:port/index.html).
My program understands that I'm asking for the right file but I can't execute the .html file in web-browser (just trying to display the date).
I've been looking online for references but maybe I'm not looking in the right direction or I'm just overlooking something.
Also the response.end doesn't print onto the web-browser even though other functions with response.end it works perfectly.
function doHTML(http_request, response)
{
// Read the requested file content from file system
fs.readFile('MYHTML/' + http_request, function (err, data) {
console.log('Hey youre in the HTML function');
response.end('Hey you got it working');
});
}
I'm fairly new to NodeJS as well, but I believe the following link may help you out:
https://expressjs.com/en/api.html#res.render
Also, I believe response.end('..text and stuff..') would send the text to your web/desktop client, so that you can process the response there: print it, parse it etc. So it's understandable to me that response.end wouldn't directly print onto the web-browser as console.log would do.
Hope this helps.
Edit: Just realizing that my response assumes you're using the Express framework.
If you are using your function as a request handler for node.js it looks like you should use http_request.url instead of http_request. The following function worked for me (server skeleton from here):
const fs = require('fs')
const http = require('http')
const port = 3000
const requestHandler = (http_request, response) => {
console.log(http_request.url)
fs.readFile('MYHTML/' + http_request.url, function (err, data) {
if (! err){
console.log('Hey youre in the HTML function.');
response.write(data);
response.write('Hey you got it working');
response.end();
} else {
response.end("File not found.");
}
});
}
const server = http.createServer(requestHandler)
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log(`server is listening on ${port}`)
})
Related
I am using node.js on Windows, with express module to generate an HTML where I would like to return data from a server processed function getfiledata() (i.e. I do not want to expose my js or txt file publicly).
I have been trying to use fetch() to return the value from getfiledata().
PROBLEM: I have not been able to get the data from getfiledata() returned to fetch().
HTML
<!DOCTYPE html>
<html>
<script type="text/javascript">
function fetcher() {
fetch('/compute', {method: "POST"})
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
});
}
</script>
<input type="button" value="Submit" onClick="fetcher()">
</body>
</html>
^^ contains my fetch() function
server
var express = require("express");
var app = express();
var compute = require("./compute")
app.post('/compute',compute.getfiledata);
compute.js
var fs = require('fs');
module.exports={
getfiledata: function() {
console.log("we got this far");
fs.readFile("mytextfile.txt", function (err, data) {
if (err) throw err;
console.log("data: " + data);
return data;
})
}
}
^^ contains my server side function
Note: from compute.js the console successfully logs:
we got this far
data: this is the data in the text file
but doesn't log from:
console.log(JSON.stringify(myJson)) in the HTML
I suspect this is due to the fact I have not set up a "promise", but am not sure, and would appreciate some guidance on what the next steps would be.
I think you're on the way. I'd suggest making a few little changes, and you're all the way there.
I'd suggest using fs.readFileSync, since this is a really small file (I presume!!), so there's no major performance hit. We could use fs.readFile, however we'd need to plug in a callback and in this case I think doing all this synchronously is fine.
To summarize the changes:
We need to call getFileData() on compute since its a function.
We'll use readFileSync to read your text file (since it's quick).
We'll call res.json to encode the response as json.
We'll use the express static middleware to serve index.html.
To test this out, make sure all files are in the same directory.
Hit the command below to serve:
node server.js
And then go to http://localhost/ to see the web page.
server.js
var express = require("express");
var compute = require("./compute");
var app = express();
app.use(express.static("./"));
app.post('/compute', (req, res, next) => {
var result = compute.getfiledata();
res.status(200).json({ textData: result } );
});
app.listen(80);
compute.js
var fs = require('fs');
module.exports = {
getfiledata: function() {
console.log("we got this far");
return fs.readFileSync("mytextfile.txt", "utf8");
}
}
index.html
<!DOCTYPE html>
<html>
<script type="text/javascript">
function fetcher() {
fetch('/compute', {method: "POST"})
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
document.getElementById("output").innerHTML = "<b>Result: </b>" + myJson.textData;
});
}
</script>
<input type="button" value="Submit" onClick="fetcher()">
<br><br>
<div id="output">
</div>
</body>
</html>
mytextfile.txt
Why, then, ’tis none to you, for there is nothing either good or bad, but thinking makes it so.
You have a couple problems here. First, you can't directly return asynchronous data from getfiledata(). See How do I return the response from an asynchronous call? for a full description of that issue. You have to either use a callback to communicate back the asynchronous results (just like fs.readFile() does) or you can return a promise that fulfills to the asynchronous value.
Second, a route handler in Express such as app.post() has to use res.send() or res.write() or something like that to send the response back to the caller. Just returning a value from the route handler doesn't do anything.
Third, you've seen other suggestions to use synchronous I/O. Please, please don't do that. You should NEVER use synchronous I/O in any server anywhere except in startup code because it absolutely ruins your ability for your server to handle multiple requests at once. Instead, synchronous I/O forces requests to be processed serially (with the whole server process waiting and doing nothing while the OS is fetching things from the disk) rather than letting the server use all available CPU cycles to process other requests while waiting for disk I/O.
Keeping these in mind, your solution is pretty simple. I suggest using promises since that's the future of Javascript and node.js.
Your compute.js:
const util = require('util');
const readFile = util.promisify(require('fs').readFile);
module.exports= {
getfiledata: function() {
return readFile("mytextfile.txt");
}
}
And, your server.js:
const express = require("express");
const compute = require("./compute");
const app = express();
app.use(express.static("./"));
app.post('/compute', (req, res) => {
compute.getfiledata().then(textData => {
res.json({textData});
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
app.listen(80);
In node.js version 10, there is an experimental API for promises built-in for the fs module so you don't even have to manually promisify it like I did above. Or you can use any one of several 3rd party libraries that make it really easy to promisify the whole fs library at once so you have promisified versions of all the functions in the module.
I have the following code. Where i upload the file first and then i read the file and console the output like console.log(obj). But the response comes first and the python scripts runs behind the scene. How can i make code to wait for the python script to run then proceed?
router.post(`${basePath}/file`, (req, res) => {
//Upload file first
PythonShell.run('calculations.py', { scriptPath: '/Path/to/python/script' }, function (err) {
console.log(err);
let obj = fs.readFileSync('Path/to/file', 'utf8');
console.log(obj);
});
return res.status(200).send({
message : 'Success',
});
});
I cannot get console.log(obj); output because it runs after the response. How can i make it wait for the python script to run and get console.log(obj) output on console.
To return the result after some async operation, you should call res.send inside the done-callback.
router.post(`${basePath}/file`, (req, res) => {
//Upload file first
PythonShell.run('calculations.py', { scriptPath: '/Path/to/python/script' }, function (err) {
console.log('The script work has been finished.'); // (*)
if(err) {
res.status(500).send({
error: err,
});
console.log(err);
return;
}
let obj = fs.readFileSync('Path/to/file', 'utf8');
console.log(obj); // (**)
res.status(200).send({
message : 'Success',
});
});
});
Then if you will not see the log (*) in the console, then it would mean that the script does not work or works improperly. The callback is not being called. First of all, you need to be sure that the script (PythonShell.run) works and the callback is being called. The POST handler will wait until you call res.send (with no matter of delay value), so that callback is the main point.
Also readFileSync could fail. In case of readFileSync failure you should see an exception. If it's ok then you'll see the next log (**) and the response will be sent.
I see PythonShell in your code. I have no experience with it, but after some reading I think that the problem could be in how you are using it. It seems the python-shell npm package, so following it's documentation you may try to to instantiate a python shell for your script and then to use listeners:
let pyshell = new PythonShell('calculations.py');
router.post(`${basePath}/file`, (req, res) => {
pyshell.send(settings); // path, args etc
pyshell.end(function (err) {
console.log('The script work has been finished.');
if(err) { res.status(200).send({ error: err }); }
else { res.status(200).send({ message : 'Success' }); }
});
});
This approach could be more appropriate because the pyton shell is kept open between different POST requests. This depends on your needs. But I guess it does not solve the problem of script running. If you are sure that the script itself is fine, then you need just to run it properly in the Node environment. There are some points:
path to script
arguments
other settings
Try to remove all arguments (create some new test script), cleanup settings object (keep only path) and execute it from Node. Handle its result in Node. You should be able to run the simplest script by correct path! Research how to setup correct scriptPath. Then add an argument to your script and run it with an argument. Hanlde the result again. There are not so many options, but each of them could be the cause of improper call.
I'm building a bar code scanning app using the node-serialport. Where I'm stuck is making a AJAX call to trigger a scan and then have Express server respond with the data from the readable stream.
Initialize Device:
// Open device port
var SerialPort = require('serialport');
var port = '/dev/cu.usbmodem1411';
var portObj = new SerialPort(port, (err) => {
if(err) {
console.log('Connection error ' + err);
}
});
//Construct device object
var Scanner = {
// Trigger Scan
scan : () => {
portObj.write(<scan cmd>), (err) => {
if(err) {
console.log('Error on scan' + err);
}
});
}
}
I've tried two approaches and neither produce the 'scan-read-respond' behavior I'm looking for.
First, I tried putting a event listener immediately following a scan, then using a callback in the listener to respond to the AJAX request. With this approach I get a 'Can't set headers after they are sent' error'. From what I understand Node is throwing this error because res.send is being called multiple times.
First Approach -- Response as callback in listener:
app.get('/dashboard', (req, res) => {
Scanner.scan(); //fire scanner
portObj.on('data', (data) => {
res.send(data); //'Can't set headers after they are sent' error'
});
}
In the second approach, I store the scan data into a local variable ('scanned_data') and move the response outside the listener block. The problem with this approach is that res.send executes before the scanned data is captured in the local variable and so comes up as 'undefined'. Also intriguing is the scanned_data that is captured in the listener block seems to multiple with each scan.
Second Approach -- Response outside listener:
app.get('/dashboard', (req, res) => {
var scanned_data; //declare variable outside listener block
Scanner.scan(); //trigger scan
portObj.on('data', (data) => {
scanned_data = data;
console.log(scanned_data); //displays scanned data but data multiplies with each scan. (e.g. 3 triggers logs 'barcode_data barcode_data barcode_data')
});
console.log(scanned_data); //undefined
res.send(scanned_data);
}
I'm a front end developer but have gotten to learn a lot about Node trying to figure this out. Alas, I think I've come to a dead end at this point. I tinkered with the .pipe() command, and have a hunch that's where the solution lies, but wasn't able to zero in on a solution that works.
Any thoughts or suggestions?
You should not make assumptions about what chunk of data you get in a 'data' event. Expect one byte or many bytes. You need to know the underlying protocol being used to know when you have received a full "message" so you can stop listening for data. At that point you should then send a response to the HTTP request.
I'm just really new on Node and Express. Trying to pass a function instead of text on my route but it seems not working. I just looked up at documentation there, They mentioned only text with req.send() method. I'm trying to pass here function's but it's not working. and also the alert() not working like this req.send(alert('Hello world')) it say's alert isn't defined or something similar.
**Update: ** I'm trying to execute this library with express and node https://github.com/przemyslawpluta/node-youtube-dl
I'm trying to do here pass functions like this
function blaBla() {
var youtubedl = require('youtube-dl');
var url = 'http://www.youtube.com/watch?v=WKsjaOqDXgg';
// Optional arguments passed to youtube-dl.
var options = ['--username=user', '--password=hunter2'];
youtubedl.getInfo(url, options, function(err, info) {
if (err) throw err;
console.log('id:', info.id);
console.log('title:', info.title);
console.log('url:', info.url);
console.log('thumbnail:', info.thumbnail);
console.log('description:', info.description);
console.log('filename:', info._filename);
console.log('format id:', info.format_id);
});
}
app.get('/', (req, res) => {
res.send(blaBla());
})
**Instead of **
app.get('/', function (req, res) {
res.send('Hello World!')
})
I hope you guy's understood my question.
res.send() expects a string argument. So, you have to pass a string.
If you want the browser to execute some Javascript, then what you send depends upon what kind of request is coming in from the browser.
If it's a browser page load request, then the browser expects an HTML response and you need to send an HTML page string back. If you want to execute Javascript as part of that HTML page, then you can embed a <script> tag inside the page and then include Javascript text inside that <script> tag and the browser will execute that Javascript when the page is parsed and scripts are run.
If the route is in response to a script tag request, then you can return Javascript text as a string and you need to make sure the MIME type appropriately indicates that it is a script.
If the route is in response to an Ajax call, then it all depends upon what the caller of the Ajax call expects. If they expect a script and are going to execute the text as Javascript, then you can also just send Javascript text as a string. If they expect HTML and are going to process it as HTML, then you probably need to embed the <script> tag inside that HTML in order to get the Javascript executed.
In your example of:
response.send(blaBla());
That will work just fine if blaBla() synchronously returns a string that is formatted properly per the above comments about what the caller is expecting. If you want further help with that, then you need to show or describe for us how the request is initiated in the browser and show us the code for the blaBla() function because the issue is probably in the blaBla() function.
There are lots of issues with things you have in your question:
You show req.send(alert('Hello world')) in the text of your question. The .send() method belongs to the res object, not the req object (the second argument, not the first). So, that would be res.send(), not req.send().
In that same piece of code, there is no alert() function in node.js, but you are trying to execute it immediately and send the result with .send(). That won't work for a bunch of reasons.
Your first code block using blaBla() will work just fine as long as blaBla() returns a string of the right format that matches what the caller expects. If that doesn't work, then there's a problem with what blaBla() is doing so we need to see that code.
Your second code block works because you are send a string which is something the caller is equipped to handle.
Update now that you've shown the code for blaBla().
Your code for blaBla() does not return anything and it's asynchronous so it can't return the result. Thus, you cannot use the structure response.send(blaBla());. There is no way to make that work.
Instead, you will need to do something different like:
blaBla(response);
And, then modify blaBla() to call response.send(someTextValue) when the response string is known.
function blaBla(res) {
var youtubedl = require('youtube-dl');
var url = 'http://www.youtube.com/watch?v=WKsjaOqDXgg';
// Optional arguments passed to youtube-dl.
var options = ['--username=user', '--password=hunter2'];
youtubedl.getInfo(url, options, function(err, info) {
if (err) {
res.status(500).send("Internal Error");
} else {
console.log('id:', info.id);
console.log('title:', info.title);
console.log('url:', info.url);
console.log('thumbnail:', info.thumbnail);
console.log('description:', info.description);
console.log('filename:', info._filename);
console.log('format id:', info.format_id);
// construct your response here as a string
res.json(info);
}
});
}
Note also that the error handling does not use throw because that is really not useful inside an async callback.
No one just could help me with that and after finding things are alone I got to know how to do this. In express there is something called middleware we have to use that thing to get this kind of matter done. Those who are really expert or have working experience with express they know this thing.
to using functions with express you need to use middleware.
like below I'm showing
const express = require('express')
const youtubedl = require('youtube-dl');
const url = 'https://www.youtube.com/watch?v=quQQDGvEP10';
const app = express()
const port = 3000
function blaBla(req, res, next) {
youtubedl.getInfo(url, function(err, info) {
console.log('id:', info.id);
console.log('title:', info.title);
console.log('url:', info.url);
// console.log('thumbnail:', info.thumbnail);
// console.log('description:', info.description);
console.log('filename:', info._filename);
console.log('format id:', info.format_id);
});
next();
}
app.use(blaBla);
app.get('/', (request, response) => {
response.send('Hey Bebs, what is going on here?');
})
app.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log(`server is listening on ${port}`)
})
And remember that you must need to use app.use(blaBla); on top of getting your route. Otherwise this might not work.
I might be out of depth but I really need something to work. I think a write/read stream will solve both my issues but I dont quite understand the syntax or whats required for it to work.
I read the stream handbook and thought i understood some of the basics but when I try to apply it to my situation, it seems to break down.
Currently I have this as the crux of my information.
function readDataTop (x) {
console.log("Read "+x[6]+" and Sent Cached Top Half");
jf.readFile( "loadedreports/top"+x[6], 'utf8', function (err, data) {
resT = data
});
};
Im using Jsonfile plugin for node which basically shortens the fs.write and makes it easier to write instead of constantly writing catch and try blocks for the fs.write and read.
Anyways, I want to implement a stream here but I am unsure of what would happen to my express end and how the object will be received.
I assume since its a stream express wont do anything to the object until it receives it? Or would I have to write a callback to also make sure when my function is called, the stream is complete before express sends the object off to fullfill the ajax request?
app.get('/:report/top', function(req, res) {
readDataTop(global[req.params.report]);
res.header("Content-Type", "application/json; charset=utf-8");
res.header("Cache-Control", "max-age=3600");
res.json(resT);
resT = 0;
});
I am hoping if I change the read part to a stream it will allievate two problems. The issue of sometimes receiving impartial json files when the browser makes the ajax call due to the read speed of larger json objects. (This might be the callback issue i need to solve but a stream should make it more consistent).
Then secondly when I load this node app, it needs to run 30+ write files while it gets the data from my DB. The goal was to disconnect the browser from the db side so node acts as the db by reading and writing. This due to an old SQL server that is being bombarded by a lot of requests already (stale data isnt an issue).
Any help on the syntax here?
Is there a tutorial I can see in code of someone piping an response into a write stream? (the mssql node I use puts the SQL response into an object and I need in JSON format).
function getDataTop (x) {
var connection = new sql.Connection(config, function(err) {
var request = new sql.Request(connection);
request.query(x[0], function(err, topres) {
jf.writeFile( "loadedreports/top"+x[6], topres, function(err) {
if(err) {
console.log(err);
} else {
console.log(x[6]+" top half was saved!");
}
});
});
});
};
Your problem is that you're not waiting for the file to load before sending the response. Use a callback:
function readDataTop(x, cb) {
console.log('Read ' + x[6] + ' and Sent Cached Top Half');
jf.readFile('loadedreports/top' + x[6], 'utf8', cb);
};
// ...
app.get('/:report/top', function(req, res) {
// you should really avoid using globals like this ...
readDataTop(global[req.params.report], function(err, obj) {
// setting the content-type is automatically done by `res.json()`
// cache the data here in-memory if you need to and check for its existence
// before `readDataTop`
res.header('Cache-Control', 'max-age=3600');
res.json(obj);
});
});