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));
Related
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.
I would like to do the following inside a client side java script from a file hosted using node and express
var rootURL = <%= "someurlfromserverconfig" %>;
I simply host a web directory from my node app. I have no need for template engines. I just want to access some simple server properties for examples an API URL. ASP and PHP have a similar feature.
Simple things as that are easy to handle with toString and replace:
var url = 'example.com'
app.get('/', function(req, res, next) {
fs.readFile('index.html', function(err, data) {
if (err) return res.sendStatus(500)
res.set('Content-Type', 'text/html')
res.send(data.toString().replace('<%= "someurlfromserverconfig" %>', '"' + url + '"'))
})
})
This would yield: var rootUrl = "example.com";
For caching purposes you might want to read the file into memory and run your replace beforehand instead of on each request, but that's your choice.
To elaborate on the workflow; fs.readFile returns a Buffer that you can run toString() on which then allows you to run replace().
If you are intent on not having to process a template on every request, and if the data you want to include are not going to change on the fly, you might consider ES6 template strings. You could host your code in a file like this:
'use strict';
const config = require('./server-config');
module.exports = `
var rootURL = "${config.rootURL}";
// ...
`;
And then you would require the file in whatever file is handling the routing. The template will only be processed once, even if it is required by multiple files.
Alternatively, you could just use a lightweight template engine, render it once, and then serve it whenever it is requested. If you want to use exactly that format, I would recommend EJS.
'use strict';
const ejs = require('ejs');
const config = require('./server-config');
let template = fs.readFileSync('./some-template.js', 'utf8');
let rendered = ejs.render(template, config);
app.get('/', (req, res) => {
res.send(rendered);
});
If the data you are sending are constantly changing, you will have to render the template every time. Even ASP and PHP have to do that under the hood.
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
I am building a webservice, for which i am using nodejs, phantomjs and expressjs. I am learning all the three.
I want to serve a delayed response to the clients after processing their query. Like for example,
I am processing certain inputs from my client, then, i want to process the data at the backend which will take approx 10 sec on an avg. Then i wanted to serve this page to the client.
Is it possible in node to send multiple responses to the same request or delayed responses so that the template will automatically update the contents.
Or , should i use the same method , like store the json in a file in the server , then serve the page with ajax which will query the page.
please help me. here is the code which i wrote ,
app-server.js(the main file):
// import express module
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
// define all required template files to be served and also define the template engine
app.engine('.html', require('ejs').__express);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
// Useful modules
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// import the routes
require('./router')(app);
app.listen(8080);
router.js:
var crypto = require('crypto');
var express = require('express');
module.exports = function (app) {
// define the static routes.
app.use('/static', express.static('./static'));
app.use('/media', express.static('./media'));
//defining the controller.
var parserlib = require('./controller.js')
// Define the home root path
app.get('/', function (req, res) {
// shows the home search page.
res.render('index', {content:'template success'});
});
app.get('/search', function(req, res){
res.redirect('/');
});
app.post('/search', parserlib.parserlib);
}
controller.js:
var crypto = require('crypto');
var path = require('path')
var childProcess = require('child_process')
exports.parserlib= function(req, res){
var output = '';
var url = req.body.search_url;
var childArgs = [
path.join(__dirname, 'external-script.js'),
url,
]
// execute the script in a separate thread.
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
// handle results
console.log(stdout);
output = stdout;
//console.log(err);
//res.send(output);
});
//res.send(output);
};
so , what i want to see is, first send a response to client stating that its loading, then i want to update the with processed data. In other languages its not possible to send multiple responses. Not sure about nodejs.
Also, do i have to store the json output from the processed lib to a file and then use ajax to query ? or is it possible to directly update the json object to the client ?
Thanks
This is just not how HTTP works. The clients won't expect it. This has nothing to do with Node or any other framework. The way to do what you're attempting is to actually send a response that the thing is loading, and then have some other mechanism for reporting state.
As an example, you might design a RESTful API. In that RESTful API you might define a endpoint for creating new things:
POST /api/things
The client would post data to that to create a new thing. The response should be something that provides a location of the newly created resource, for example an HTTP 301 to /api/things/1.
If the user goes to /api/things/1 and the thing isn't done getting made yet, then you can either do a temporary redirect (303) to /api/things/1/status which provides some helpful status information, or just issue a 404.
If you actually want to send back server-side pushes of status information, then you should be looking at WebSockets or a pure Socket API of some kind, neither of which is provided by Express, but both of which are available in Node (checkout the socket.io library and the net core library)
I am making a game for TWO players with node.js, socket.io and express.
In order to avoid effect from the third person that come to play, i want to generate specific URL for the two who are ready to play.
So my question is, how to change the URL when two people have come?
I am now testing it in local. In the server side, i have server listen to a port.
var express = require('express');
var SocketIO = require('socket.io');
var http = require('http');
var path = require('path');
var app = express({
views: path.join(__dirname, 'views')
});
app.use('/assert', express.static(path.join(__dirname, 'assert')));
app.engine('html', require('ejs').renderFile);
app.get('/', function (req, res) {
res.render('home.html', {layout: false});
});
var server = http.createServer(app);
var sio = SocketIO.listen(server);
server.listen(8080);
function(...){...}
In the client side, i have socket connected to somewhere.
var socket = io.connect('http://' + location.host);
var ....
i guess what i need to do is to provide a button when i detect that two clients come in.
When they clicked it, it direct them to a generated new URL.
So there is an old URL and many new ones...
Then how can i set different URLs in both server and client??
Any help is appreciated^ ^
There are many ways for generating a UNIQUE random url
1) Use Timestamp and append it to a predefined url of yours
2) Use random number generators. This can be done either by pure javascript function Math.Random() or even the one provided by node
Eg.
var url = "http://www.yourHostName.com/"+(Math.Random()*(UpperLimit-LowerLimit)+(LowerLimit));
Supply Large UpperLimit Like 100000 (According to your need and expected traffic) and LowerLimit = 0;
or by using the time stamp like this:
var url = "http://www.yourHostName.com/"+ new Date.getTime();
Beside this as I said you can also use the node to do the same task. There is a module called node-uuid which can do the similar task Refer to this Question: generate URL on node.js server
Once you have the unique URL and the reference to the clients to whom you want to send to a same Generated URL. Then Just Redirect them using the following:
response.writeHead(301,
{Location: url}; //one you generated
);
response.end();