Node JS - call function on server from client javascript - javascript

I have written a server.js. Below is the code:-
var http = require('http');
var fs = require('fs');
var my_code = require('./my_code');
function send404Response (response) {
response.writeHead(404, {"Context-Type" : "text\plain"});
response.write("Error 404: Page not found");
response.end();
}
function onRequest(request, response) {
if (request.method == 'GET' && request.url == '/') {
response.writeHead(200, {"Context-Type" : "text\plain"});
fs.createReadStream ('./index.html').pipe(response);
} else {
send404Response(response);
}
}
http.createServer(onRequest).listen(8888);
console.log("Server is now running");
Another server side js written in node is my_code.js. Below is the code:-
var https = require('https');
module.exports.func = myFunction;
function myFunction(myParam) {
console.log (myParam);
}
myFunction(myParam) should be called from client side javascript which will pass myParam. But client side javascript is throwing error saying myFunction is not found.
Please find HTML which contains client side javascript below:-
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#button').click(function() {
$.ajax('/', function(list) {
myFunction($('#myField').text()); //How to do it
});
});
});
</script>
</head>
<form>
<div id="contactno">myField:<input type="text" name="myField"> </div>
<div id="button"><input type="button" value="Submit"></div>
</form>
</html>
Before hitting above html page, I am running node server.js
Please let me know best way to call myFunction from client side.
Thanks in Advance.

Obviously, as you've figured out, you cannot call this function on the client as it's not available there. So your client has to call the server, right?
So the client code would have to pass the $('#myField').text() to the server, and server would have to have another endpoint to receive this, call myFunction on this, and return the result.
You can do it in many different ways, here is one simple example.
Expand the server with another endpoint
function onRequest(request, response) {
if (request.method == 'GET' && request.url == '/') {
response.writeHead(200, {"Context-Type" : "text\plain"});
fs.createReadStream ('./index.html').pipe(response);
} else if (request.method === 'POST' && request.url == '/do-work') {
// asuming sync as in your example
let result = my_code.func(request.body);
response.writeHead(200, {"Context-Type" : "application/json"});
response.write(JSON.stringify({
result: result
});
response.end();
} else {
send404Response(response);
}
}
(I'm not touching on some not-so-good practices and codes here to keep my answer focused to your question.)
You would also have to extend your client code.
$('#button').click(function() {
$.ajax('/', function(list) {
$.ajax({
type: 'POST',
url: '/do-work',
data: $('#myField').text()
success: function(result) {
console.log('Response:', result);
}
}
});
});

Related

Show new html page after post request?

1. Summarize the problem
First I want to describe, how the project should work. I want to build my own little website with html, css, javascript (and expressJS and nodeJS). I´ve also watched a few tutorials about Rest-APIs and how they work. I want to create a login page, where you should enter a password to get to the "main- page".
The problem is, that I´m working with a post-request atfer the user has clicked on a "submit" - button, where the value of a password box will be send to a server to check. After this was executed, I dont know how to show the new html page and how to redirect the user to a new page.
2. Describe what you´ve tried & 3. Show some code
I´ve tried two different things. Here is my beginning of the code in my server.js:
var app = express();
var server = app.listen(3000);
app.use(express.static('website'));
First I wanted to send a file after checking the password in my post request:
app.post('/all', function(req, res) {
if(req.body.password != 'example') {
return
}
res.sendFile('index.html');
});
I found this github issue, where a user has the same problem: https://github.com/expressjs/express/issues/692
But this method doesnt seem to work in a post-request. So I´ve tried another thing. I already knew, that sendFile() works in a get-request (as I mentioned in a github issue), so I´ve made this:
app.get('/all', function(req, res) {
res.sendFile('index.html');
});
app.post('/register', function(req, res) {
if(req.body.password != 'example') {
return
}
res.redirect('/all')
});
For this code example I used the following stack overflow page: How to redirect to another page after serving a post request in Node.js? but it didnt work either.
3. Show some code:
Script in html doc :
function XHTML_POST(path, parms, callback) {
req = new XMLHttpRequest();
var ret = false;
callbackPOST = callback;
req.open("POST", path, true);
req.onload = function () {
if (req.status != 200 && req.status != 1223 && req.status != 0 && req.status != 204) {
if (req.status == 401) { }
else { }
}
else {
callbackPOST = callback;
}
}
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
req.setRequestHeader("Cache-Control", "no-cache");
req.send(parms);
}
function postPass() {
var pass = document.getElementById('pwBox').value; //id of passwordbox
XHTML_POST('/register', 'password=' + pass, callback)
}
function callback() { }
</script>
After clicking on a submit button the postPass() function will be executed. Hopefully you understood my problem and what I´m trying to make. Thanks for reading it.
You can use the html forms :
HTML :
<form method="POST">
<input type="email" name="youremail" placeholder="Email Address" required>
<input type="text" name="yourname" placeholder="Name" required>
<input class="subscribe-button" type="submit" value="Subscribe">
</form>
NodeJs Server :
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, 'login.html'))
})
app.post("/", (req, res) => {
//Your Password Verification
if(true){
res.sendFile(path.join(__dirname, 'index.html'))
}else{
res.sendFile(path.join(__dirname, 'login.html'))
}
})

How does one load a different html page from the same Express controller script?

I want to change the first page (login page), after some defined action has been performed on it, with a second page (admin dashboard) from the same controller in Express.
Here's my controller code from nimda.js that matters:
function handlePut(req, res){
let html = fs.readFileSync(path.join(__dirname,'../static/feed.html'));
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
}
router.put('/', handlePut);
// This handles the form submitted.
router.post('/', function(req, res){
if(req.body.pwd != '1234')
res.send('False');
else
{
//Doesn't work from here.
handlePut(req, res);
}
});
//This is when server.js routes the request to this script
router.get('/', function( req, res){
let html = fs.readFileSync(path.join(__dirname,'../static/login_nimda.html'));
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
I thought that doing a PUT from my POST code after authentication would help me send a new HTML page as a response. The first HTML page is login_nimda.html that does the POST request to /nimda.
This doesn't work and I stay on the same login_nimda.html. The POST request works properly though.
Here's the script of my login_nimda.html:
<script>
$('#submit').on('click', function(){
var form = $('#log').serialize();
$.post('/nimda', form).done(function(data) {
if(data=="False" && $('#err').length==0){
$('#log').prepend('<p id = "err" class = "alert alert-info" align = "centre" > Incorrect!</p>');
}
else
{
$('#err').remove();
document.location.href = '/nimda/'+data;
}
});
});
</script>
Any alternatives to this approach are most welcome.
Okay, so I could come up with two totally non-secure ways-
1. Passing the password as method information post authentication
The script under login_nimda.html is modified to send a request to the same controller nimda.js:
$.post('/nimda', form).done(function(data) {
if (data == "False" && $('#err').length == 0) {
$('#log').prepend('<p id = "err" class = "alert alert-info" align = "centre" > Incorrect!</p>');
} else {
$('#err').remove();
document.location.href = '/nimda/'+$('input[type="password"]').val();
}
});
Since the password will be present in the URL only post successful authentication, only an authorized user would see it - Downside: The password with the URL gets cached
nimda.js is modified to load the "second page":
//the handler I added
router.get('/your_password', function(req, res){
let html = fs.readFileSync(path.join(__dirname,'../static/second_page.html'));
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
//for login authentication
router.post('/', function(req, res){
if(req.body.pwd != '1234')
res.send('False');
else
res.send('True');
});
2. Passing a random string to the controller in the method information post authentication
Hmmm, I've no better option currently
The script under login_nimda.html is modified to send a request to the same controller nimda.js but this time, not passing the password but a random string received post authentication as an access key:
<script>
$('#submit').on('click', function(){
var form = $('#log').serialize();
$.post('/nimda', form).done(function(data) {
if(data=="False" && $('#err').length==0){
$('#log').prepend('<p id = "err" class = "alert alert-info" align = "centre" > Incorrect!</p>');
}
else
{
$('#err').remove();
document.location.href = '/nimda/'+data;
}
});
});
</script>
nimda.js is modified to add a new route handler only every time authentication is successful with the route /nimda/new_random_string and the key (new_random_string) is passed as a response so that the control moves to the new handler to display the second page:
var key = '';
function createRandomString( length ) {
var str = "";
for ( ; str.length < length; str += Math.random().toString( 36 ).substr( 2 ) );
key = str.substr( 0, length );
return key;
}
router.post('/', function(req, res){
if(req.body.pwd != '1234')
res.send('False');
else
{
router.get('/'+ createRandomString(16), function(req, res){
let html = fs.readFileSync(path.join(__dirname,'../static/feed.html'));
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
res.send(key);
}
});
This way the key can changes with every request and so cache is rendered useless.
Please let me know a better solution. I know there is!
When you send your POST request in JavaScript, you are in the browser (client side). The response to that request will be received by the browser, as text data, containing HTML or whatever the server sent.
If as a response to the data you received in JavaScript you want to move to another page, you must do that in JavaScript.
In JavaScript you will use window.location:
$.post('/nimda', form).done(function(data) {
if (data == "False" && $('#err').length == 0) {
$('#log').prepend('<p id = "err" class = "alert alert-info" align = "centre" > Incorrect!</p>');
} else {
$('#err').remove();
document.location.href = '/some-page.html';
}
});

Node.js, Express: How can I handle res.send values with the client

I'm a newbie in node.js, and I'm also using express.
I build a simple web application to upload files to a server, and save them, when they are okay. That works fine, but now I want to inform the client about the current state( is it uploaded or did it not work, because of the large size from the file).
I know that I should use res.send(), but I want to display it on the same page( with all elements on "upload.html"), where the client uploaded the file. I guess, I have to using client sided javascript to work with the sended information, but how do I communicate with server side javascript and client side javascript? Or do I not need to use client sided javascript?
(I would like to combine it later with HTML, so I can design the answer from the server with CSS.)
server.js:
var express = require('express'),
fileUpload = require('express-fileupload'),
fs = require('fs'),
obSizeOf = require('object-sizeof'),
app = express();
app.use(express.static("public"));
app.use(fileUpload());
app.get("/upload.html", function(req, res){
res.sendfile(__dirname + "/" +"upload.html");
})
app.post('/upload.html', function(req, res) {
if(obSizeOf(req.files.sampleFile) > 10000000)
{
res.send("The size of the not-uploaded file is to large! Please use a file with a maximal size of 10MB");
return;
}
else
{
var sampleFile;
if (req.files.sampleFile.name == "") {
res.send('No files were uploaded.');
return;
}
else
{
sampleFile = req.files.sampleFile;
var typ = sampleFile.mimetype.split("/");
console.log(typ[0]);
if(fs.existsSync("public/upload/image/"+typ[0]+"/"+sampleFile.name))
{
res.send("A File with the same name already exists! Please rename it!");
return;
}
else
{
sampleFile.mv('public/upload/'+typ[0]+'/'+sampleFile.name , function(err) {
if (err){
res.send('File NOT UPLOADED!');
}
else { console.log("Mieeep!"); res.send(typ[0].charAt(0).toUpperCase()+typ[0].slice(1) +' data uploaded!');
}
});
}
}
}
});
app.listen("8000");
/upload.html:
<html>
<body>
<form ref='uploadForm'
id='uploadForm'
action='/upload.html'
method='post'
encType="multipart/form-data">
Upload File
</br>
<input type="file" name="sampleFile" />
</br>
<input type='submit' value='Upload!' />
</br>
<p id="serverInformation"></p> <!--Placeholder for information from the server-->
Only images
</form>
</body>
</html>
What you actually need is socket programming. Using node js you can do that easily.
just see this link for more on socket and node js.
you can use AJAX and check the error status. there
...
<script>
$(document).ready(function() {
$("#uploadForm").submit(function() {
$.ajax({
type: "POST",
url: "/upload.html",
data: $(this).serialize(),
complete: function(xhr, statusText){
alert(xhr.status+" : "+ statusText);
}
})
})
})
</script>

Is it possible to forward a stream from one function to another?

Please have a look at the following sample code.
As you can see, it uses busboy to parse incoming form data and write incoming files to disc.
Let's assume these are just image files because my sample code makes use of imgur.com. (a content-length header doesn't need to be sent)
The imgurUpload() function makes use of node-form-data
Is it somehow possible to stream the image files additionally, without the need to buffer them complete, to imgur.com? (to the imgurUpload() function and use it within node-form-data?)
Server / listener:
var http = require('http'),
Busboy = require('busboy'),
FormData = require('form-data'),
fs = require('fs')
http.createServer(function(req, res) {
if (req.method === 'POST') {
var busboy = new Busboy({
headers: req.headers
})
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
//pipe the stream to disc
file.pipe(fs.createWriteStream('1st-' + filename))
//pipe the stream a 2nd time
file.pipe(fs.createWriteStream('2nd-' + filename))
/* how to connect things together? */
})
busboy.on('finish', function() {
res.writeHead(200, {
'Connection': 'close'
})
res.end("upload complete")
})
return req.pipe(busboy)
} else if (req.method === 'GET') {
var stream = fs.createReadStream(__dirname + '/index.html')
stream.pipe(res)
}
}).listen(80, function() {
console.log('listening for requests')
})
HTML test form (index.html)
<!doctype html>
<head></head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="submit">
</form>
</body>
</html>
Sample function that submits an image file to imgur.com:
function imgurUpload(stream) {
var form = new FormData()
//form.append('Filedata', fs.createReadStream('test.jpg'))
form.append('Filedata', /* how to connect things together? */X )
form.submit('http://imgur.com/upload', function(err, res) {
if (err) throw err
var body = ''
res.on('data', function(chunk) { body += chunk })
res.on('end', function() { console.log('http://imgur.com/' + JSON.parse(body).data.hash) })
})
}
Update (regarding mscdex answer)
_stream_readable.js:748
throw new Error('Cannot switch to old mode now.');
^
Error: Cannot switch to old mode now.
at emitDataEvents (_stream_readable.js:748:11)
at FileStream.Readable.pause (_stream_readable.js:739:3)
at Function.DelayedStream.create (\path\node_modules\form-data\node_modules\combined-stream\node_modules\delayed-stream\lib\delayed_stream.js:35:12)
at FormData.CombinedStream.append (\path\node_modules\form-data\node_modules\combined-stream\lib\combined_stream.js:45:30)
at FormData.append (\path\node_modules\form-data\lib\form_data.js:43:3)
at imgurUpload (\path\app.js:54:8)
at Busboy.<anonymous> (\path\app.js:21:4)
at Busboy.emit (events.js:106:17)
at Busboy.emit (\path\node_modules\busboy\lib\main.js:31:35)
at PartStream.<anonymous> (\path\node_modules\busboy\lib\types\multipart.js:205:13)
You can append Readable streams as shown in node-form-data's readme. So this:
form.append('Filedata', stream);
should work just fine.
Then in your file event handler:
imgurUpload(file);

Passing a JSON object from clientside JavaScript to NodeJS

I have a webpage which creates a JSON object based on user input. I would like to then somehow allow the user to submit this JSON object to a NodeJS script for processing/insertion into a MySQL database. However, I'm really not sure how to do something like this -- the best I can come up with is some form of a POST, but I'm not sure where to start with this.
Because I don't know what such a method would be described as, I haven't had much success in locating any tutorials or other resources online.
Could anyone suggest some articles or documentation to look at that would be relevant to something like this? Or, at least, tell me what to search for? Thanks.
EDIT: This is the code I am trying to get working at the moment. I'm just trying to convert the POST data type from string to JSON on both sides.
Serverside:
var express = require('express');
var fs = require('fs');
var app = express();
app.use(express.bodyParser());
app.get('/', function(req, res){
console.log('GET /')
//var html = '<html><body><form method="post" action="http://localhost:3000">Name: <input type="text" name="name" /><input type="submit" value="Submit" /></form></body>';
var html = fs.readFileSync('index.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
app.post('/', function(req, res){
console.log('POST /');
console.dir(req.body);
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('thanks');
});
port = 8080;
app.listen(port);
console.log('Listening at http://localhost:' + port)
Clientside:
<html>
<body>
<form method="post" action="http://localhost:8080">
Name: <input type="text" name="name" />
<input type="submit" value="Submit" />
</form>
<script type="text/JavaScript">
console.log('begin');
var http = new XMLHttpRequest();
var params = "text=stuff";
http.open("POST", "http://localhost:8080", true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//http.setRequestHeader("Content-length", params.length);
//http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() {
console.log('onreadystatechange');
if (http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
else {
console.log('readyState=' + http.readyState + ', status: ' + http.status);
}
}
console.log('sending...')
http.send(params);
console.log('end');
</script>
</body>
</html>
Here is a very basic example using jQuery to do the post request and an express app. I think it should be a decent starting point.
// client side, passing data to the server
$.post("/foo/", { data : { foo : "bar" } }, function(temp) {
// temp === "I am done";
});
// serverside app.js
var express = require("express");
var app = express();
// will parse incoming JSON data and convert it into an object literal for you
app.use(express.json());
app.use(express.urlencoded());
app.post("/foo/", function(req, res) {
// each key in req.body will match the keys in the data object that you passed in
var myObject = req.body.data;
// myObject.foo === "bar"
res.send("I am done");
});
EDIT: JSON.stringify() and JSON.parse() will serialize/deserialize JSON. (jQuery makes this much easier, but if you wanna go pure javascript)
Change to var params = "text=" + JSON.stringify({ foo : "bar" });
and
console.dir(JSON.parse(req.body.text));
It worked for me on my local.

Categories