Difficulty setting up a 'post' route in an express server issue - javascript

I'm attempting to validate that my client can post info to it's server. I've set up this 'route' in my Express server.
// server.js this is the server for the PvdEnroll application.
//
var express = require("express"),
http = require("http"),
mongoose = require( "mongoose" ),
app = express();
// static file directory for default routing
app.use(express.static(__dirname + "/client"));
app.use(express.urlencoded());
// create Express-powered HTTP server
http.createServer(app).listen(3000);
console.log("Server listening at http://127.0.0.1:3000/");
// set up a post route in the server
app.post("/selections", function (req, res) {
console.log("data has been posted to the server!");
});
app.post("/selections", function (req, res) {
console.log("Some data has been posted to the server from app.js");
})
The client uses this file:
var main = function () {
"use strict";
$.getJSON("../data/checkBoxesA.json", function(checkBoxTxt) {
checkBoxTxt.forEach(function (data) {
var $checkbox = "<input type ='checkbox' name = "
+ data.label + "id = 0 UNCHECKED/>";
$(".enroll_actions").append($checkbox);
$(".enroll_actions").append(' ' + data.label + "<br/>");
$(".enroll_actions").append(' ' + data.note + "<br/>");
$(".enroll_actions").append(' '+ "<br/>");
});
});
$(".comment-input").on("click", function (event) {
console.log("Hello World!");
// here we'll do a post to our selections route
$.post("selections", {}, function (response) {
console.log("Client says - We posted and the server responded!");
console.log("Response from server :", response);
console.log("STUBB1");
});
});
console.log("STUBB2");
};
$(document).ready(main);
In the Chrome console I'm getting:
POST file:///Users/*******/Projects/r_PE/app/PvdEnroll/client/html/selections net::ERR_FILE_NOT_FOUND
A path is being sought but a tutorial's example (which works!) and is structurally identical to mine(?) uses a name i.e. "selections" to establish a route between client and server.
I'm running the server on my Mac using Virtual Box and Vagrant.
Thanks for any clarification.

On restarting the server the log message is now "POST 127.0.0.1:3000/html/selections 404 (Not Found).
Okay. This is some helpful information!
Basically, your file structure is more or less this (some file names will be different, just look at the general structure):
Node.js code (including main .js file and the module.json)
client: a folder for your static content
html: a folder
index.html: the file you are currently using
Anyway, jQuery.post() is fed a relative path (as apposed to an absolute path). That means that, based on the location of where the code was, it will "guess" the location of the file.
That means that it was trying to find a route at [locahost:port]/html/selections when your server is listening at [localhost:port]/selections! You'll need to have jQuery post to /selections instead of just selections.
For more information, this blog post is helpful (relative paths work the same in Javascript/CSS). The helpful snippet:
Here is all you need to know about relative file paths:
Starting with "/" returns to the root directory and starts there
Starting with "../" moves one directory backwards and starts there
Starting with "../../" moves two directories backwards and starts there (and so on...)
To move forward, just start with the first subdirectory and keep moving forward

Related

Saving and loading data in a node.js server and passing it to an html5 file

So I'm very new to node.js and javascript, and i made a server that works great by loading up an html file on request. This html file does not contain any of it's own data, it simply sources from the internet and displays some images and text i wrote. I've decided to make the site play an audio file when it is opened. I know this is done easily with the <audio> tag in html5 but the src="" lets me take a file from the computer and place it there, of course when i open the site from another computer the file obviously isn't found and thus isn't played. I figure the audio file must be kept as a variable on the server and passed into the html file's <audio src= > tag. How do i do this? It is an .mp3(but i can get it to any other audio format) file about 30 seconds long. I just want it to play when the site is loaded from another computer(over the internet). Also how would i go about doing the same with pictures or any other data that i don't want to source from the internet but rather keep as data in my server?
var http = require('http');
var fs = require('fs');
var simpleServer = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type":"text/html"});
fs.readFile('./Picture.html', null, function(error, data){
if(error){
response.writeHead(404);
} else{
response.write(data);
}
response.end();
})
});
simpleServer.listen(80, '0.0.0.0', function() {
console.log('Listening to port: ' + 80);
});
console.log("Server running...");
Short Answer
Bypassing using HTML altogether, you can also simply serve the audio file instead of Picture.html:
fs.readFile("./audiofile.mp3", function(error, data) {
if (error) {
response.writeHead(404);
} else {
response.writeHead(200, { "Content-Type": "audio/mpeg"});
response.end(data, 'utf-8');
}
});
Note:
You will have to replace the filename audiofile.mp3 and the content type audio/mpeg to their appropriate values for the file you want to send.
Check Mozilla's Complete List of MIME Types for a full list of file extensions and their associated content types.
Better Answer:
The http module is fairly low-level and is unnecessarily complicated if you're learning.
You can install express.js to your project using the command npm install express --save.
With express your code simplifies to:
const express = require('express');
const app = express();
const port = 80;
app.get('/', (request, response) => {
response.sendFile(__dirname + '/Picture.html');
});
// Anything put in the public folder is available to the world!
app.use(express.static(__dirname + '/public'));
app.listen(port, () => {
console.log(`Listening on port: ${port}`)
});
Then you just have to place all your files into a folder called "public" under your project directory and you can call them from HTML!

Creating dynamic link by requesting data from front-end in Node.js and Express.js

This is kind of hard for me to explain but I am trying to shorten my code by creating one link instead of 50 for downloading a form. I will try to explain this a bit better using my code.
I have 5 get requests that do exactly the same thing but download a different file.
router.get('/form1', function (req, res) {
var file = __dirname + '/../public/forms/form1.pdf';
res.download(file);
});
router.get('/form2', function (req, res) {
var file = __dirname + '/../public/forms/form2.pdf';
res.download(file);
});
etc...
and my front-end link are;
FORM 1
FORM 2
etc...
Is there anything I can do to make this a more dynamic? The only way I can think of is something like this;
router.get('/:formName', function (req, res) {
// some how do a "req.params.formName"
var file = __dirname + '/../public/forms/' + req.params.formName + '.pdf';
res.download(file); // Set disposition and send it.
});
But I don't know how I will get the formName or if thats even possible.
Here are some more options to clarify:
Option 1: If you have a folder on the server with a fairly manageable directory structure, simply use express.static to map the physical folder to a virtual one with automatic download:
app.use('/download', express.static(path.join(__dirname, '/public/forms/')))
This will result in any link from the front-end with href='/download/something.pdf' working as long as that file is on the server in the path you mapped (i.e. in /public/forms).
Option 2 (which David E above answered in essence): In your original code, if you wanted to generate a path handler for a link that looks like /download/form1, /download/form2, it's a very minor modification:
router.get('/download/:formNumber', function (req, res) {
var file = __dirname + '/public/forms/' + req.params.formNumber + '.pdf';
res.download(file);
});
Option 3: You want to authenticate access to the files and potentially support multiple, complex URL schemes to a single handler that can lookup the appropriate physical path and send the file:
router.get('/download/:path[forms|images|files]/:formNumber1', fileRequestHandler);
router.get('/public/downloadFolder2/:formNumber2', fileRequestHandler);
router.get('/public/downloadFolder3/:formNumber3', fileRequestHandler);
function fileRequestHandler(req, res) {
// Check authentication here - example below from Passport
if(!req.isAuthenticated())
return res.status(401).send({err: 'Unauthorized'});
// Check which form number is supplied and map to appropriate physical file
if(req.params.formNumber1) {
// in this example, req.params.path can be one of three allowed sample values - forms or images or files
var file = __dirname + '/public/' + req.params.path + '/' + req.params.formNumber + '.pdf';
res.download(file);
} else if(req.params.formNumber2) {
// etc.
}
}
Note: Ezra Chang's point about path validity is important.
This response assumes that your route lives in index.js.
router.get('/form/:formName', (req, res, next) => {
res.download(`${__dirname}/../public/forms/${req.params.formName}.pdf`);
});
FORM 2
Be careful about your path. I don't know whether you can start at a directory, go up a level, then down again.

redirect url and change page after click event and serve html file to browser using GET

I am trying to redirect localhost:9000 to localhost:9000/list after the user clicks on a button in home page and use a get method to display list.html. How can I use the AJAX call I have in display.js and the get request in my routes.js to redirect url and serve up my list.html. When I click on the button, nothing happens. To change url i tried both windows.location and location.href but I am not sure if these are even needed.
Directory layout
dir main
-server.js
dir subMain
dir display
-display.js
dir routing
-routes.js
dir public
-home.html
-list.html
server.js
var path = require('path');
var express = require('express');
var app = express();
require('./subMain/routing/routes.js')(app, path, express);
app.listen(9000, function(){
console.log('connected on 9000')
})
routes.js
module.exports = function(app, path, express){
app.use(express.static("app"))
app.use(express.static(__dirname + "/public"));
app.use(express.static(__dirname + "/routing"));
app.use(express.static(__dirname + "/display"));
app.use(function(request, response, next){
response.sendFile(path.join(__dirname + "/..", "public", "home.html"));
})
app.get('/list', function(request, response){
response.sendFile(path.join(__dirname + '/..', 'public', 'list.html'));
});
}
display.js
$(document).on('click', '#btn', sendSurvery);
function sendSurvery(){
window.location = 'survey.html';
//var myQueryUrl = "http://localhost:9000/survey";
//$.ajax({url: myQueryUrl, method: 'GET', success: function(result){
// location.href = "http://localhost:9000/list"
//}}).done(function(response){
//});
}
Update: Since AJAX is not required to change html on browser, where would be a suitable place to use the windows.location, and how would I connect that to a get request to my list.html? Right now, I tried doing a get request in both the server.js file and routes.js file, but when I click on the button, the url will change to survey but not the content on the browser (list.html is not displaying)
Update 2: I got rid of the AJAX call and just used: windows.location = localhost:9000/list but the get request is not sending the list.html file to the browser. I tried putting the get request in the server.js file also, but it still will do nothing
You don't need AJAX here (A stands for Asynchronous) - you can simply do window.location = http://localhost:9000/survey
This will effectively tell browser to send a synchronous GET request to the server and replace current page with whatever it receives as response.
not sure if this is what you are looking for, but there is no survey.html in your listed tree structure....
also, if you want to do relative access, you may want to add a line similar to the below:
app.use(express.static(path.join(__dirname, 'subMain/public')));
display.js
$(document).on('click', '#btn', sendSurvery);
function sendSurvery(){
var myQueryUrl = "http://localhost:9000/";
window.location.replace(myQueryUrl + 'survey.html)
}
This would allow you to actually store myQueryUrl as a config variable elsewhere so that it could be changed based on your environment.
You also have to make sure that you link to display.js in your html file so it's initially requested from the server. The server won't just send it for you.
And you don't show the rest of your file but you might need to initializing the call to the click handler if you aren't doing that:
(function(){
$(document).on('click', '#btn', sendSurvery);
}();
As a note, GET requests (and all requests for that matter) originate on the Client and are sent to the server. So they must be placed in files being sent to the client.

Node.js, Express and Mongoose serving several static files

With Node.js, Express and Mongoose, I am serving several static files synchronously within multiple sub-directories with the following code (which works fine):
fs.readdirSync(__dirname + "/../../../np-site/themes/default/client/")
.forEach(function (dir) {
app.use(express.static(__dirname +
"/../../../np-site/themes/default/client/" + dir)
);
});
However, part of the url must be dynamic depending on a database entry value:
express.static(__dirname + "/../../../np-site/themes/" + theme + "/client/" + dir)
I have tried several different ways, to no avail. The following is the first attempt I made, which made the most sense to me at the time (the App model is a single object that can only be updated and retrieved):
App.find(function (err, appSettings) {
fs.readdirSync(__dirname + "/../../../np-site/themes/" + appSettings[0].theme +
"/client/").forEach(function (dir) {
app.use(express.static(__dirname + "/../../../np-site/themes/" +
appSettings[0].theme + "/client/" + dir)
);
});
});
This however does not work, and no static files are served as a result.
The object that I need to access is available (discovered via console.log), but something is not right.
The browser console does return an infrequent error message stating the MIME type of the files (CSS) is not correct, but I believe this is because the app cannot find correct directories (removing the method altogether has the same result).
I'm thinking that it has something to do with app.use within a Mongoose method, but I am not certain.
Could someone please shed some light towards this frustrated soul? I feel as though I am on the wrong path.
The problem is that you're adding your middleware asynchronously (because App.find() is most likely performing an asynchronous action), which causes your dynamic middleware to get added (probably) after all of your statically defined middleware and route handlers.
Express executes middleware and route handlers in the order that they are added.
The solution would be to delay adding any other middleware or route handlers until after your fs.readdirSync() (but inside your App.find() callback). A simple way to do this is to simply put your other middleware and route handler additions inside a function that you call after your fs.readdirSync():
var baseThemePath = __dirname + "/../../../np-site/themes/";
App.find(function (err, appSettings) {
var themePath = baseThemePath + appSettings[0].theme + "/client/";
fs.readdirSync(themePath).forEach(function(dir) {
app.use(express.static(themePath + dir));
});
setupStatic();
});
function setupStatic() {
app.use(express.static('public'));
app.get('/', function(req, res) {
res.send('Hello world');
});
// ...
}

Nodejs/Expressjs javascript: get where request came from

I am using nodejs with the expressjs module to create a webserver.
My current setup is this
var express = require("C:/Program Files/nodejs/node_modules/express")
var app = express();
var server = require('http').createServer(app).listen(80);
var io = require('C:/Program Files/nodejs/node_modules/socket.io').listen(server, {log:false});
var path = require("path");
fs = require("fs");
is there a way using
app.use(function(req,res,next){
//code
})
to get where a request came from? Eg, if on an html page, you have the script tag
<script src="test.js"></script>
it sends a request to retrieve test.js, can I use the req argument to see that the request for test.js came from the html page and get the full filepath of the html page?
EDIT: I'm trying to write a function that serves the correct index file (index.html/.htm/.php etc if you just enter a directory into the url ("localhost/tests/chat/"), but the problem then is, when it requests the javascript file from the index page, it goes back 1 directory too far (searches for "localhost/tests/test.js" instead of "localhost/tests/chat/test.js"), and only works if you directly type the filename into the url ("localhost/tests/chat/index.html").
My function:
app.use(function(req,res,next){
var getFullPath = path.join("public",req.path);
console.log(req.path);
if (fs.existsSync(getFullPath)) {
if (fs.statSync(getFullPath).isDirectory()) {
getFullPath = path.join(getFullPath,"index.html");
}
res.sendfile(getFullPath);
} else {
res.send("404 Not Found");
}
});
I realise you can use
app.use(express.static(__dirname + '/public'));
but this creates a problem for me with my custom php parser module so that's not really an option
I was able to use req.headers.referer to get where the javascript file was being asked from and therefore point to the correct location of the javascript file.
getFullPath = path.join("public",req.headers.referer.split(req.host)[1],path.basename(req.path));

Categories

Resources