Proxy with Express.js + Request.js - javascript

I started writing a proxy server with Express.js and Request.js
The server runs on port 900 and does:
Serve static content from path /prototype
For certain calls
forward the request to another server (on port 8080)
Resolves
/prototype/[this|that] to the corresponding static html
/prototype/this.html and /prototype/that.html.
Also serve this.html as default for /prototype
I managed to achieve 1) - 3) with following code:
var express = require('express'), path = require('path'), request = require('request');
var app = express();
app.get('/prototype', function(req, res, next) {
// a) request(req.protocol + '://' + req.get('host') + req.url + '/this').pipe(res);
// b) res.redirect('/prototype/this');
});
app.get('/prototype/:path(this|that)', function(req, res, next) {
var resolvedUrl = req.protocol + '://' + req.get('host') + req._parsedUrl.pathname + '.html';
request(resolvedUrl).pipe(res);
});
app.get('/prototype/sample/:path', function(req, res, next) {
var resolvedUrl = 'http://localhost:8080' + req.url;
request(resolvedUrl).pipe(res);
});
app
.use('/prototype', express.static(path.resolve(__dirname, '../')))
.use(app.router)
.use(express.errorHandler({
dumpException: true,
showStack: true
}));
module.exports = app;
My folder structure is
prototype
|_css
| |_<css files>
|_js
| |_<js files>
|_this.html
|_that.html
this.html refers to the files in css and in js
<link rel="stylesheet" href="css/app.css" />
<script data-main="js/app.js" src="js/require.js"></script>
In order to achieve 4) I tried to request the /prototype/this path when /prototype is requested, however then the js and css are requested from /js/app.js and /css/app.css instead of /prototype/js/app.js and /prototype/css/app.css which fails. (See a) in the code comment).
The behavior I would like to achieve can be achieved with b) but I don't want to have the URL bar in the browser changed to /prototype/this but keep it in /protoype.
Any nice way to do this?

Turned out to be a missing trailing slash.. after /prototype.
Without the trailing slash I was overriding the behaviour that redirected to the directory with trailing slash when requesting directory path without trailing slash.
Changed it to the following and it works like a charm.
app.get('/prototype/', function(req, res, next) {
// a) request(req.protocol + '://' + req.get('host') + req.url + '/this').pipe(res);
// b) res.redirect('/prototype/this');
});

Related

Serving Temporary Pages with NodeJs

I'd like to start by letting everyone know that I am new to coding in node. With that out of the way let me explain what I am trying to build, I'm trying to build a site where a user can use a button on the main page to visit a page that has a randomized route, but only once. So once you have visited that route, you need to click on the link again to see the same contents but on a different route. That will ensure users have to click on the button and can't just cheat the system by entering the same link over and over. So in basic terms I need the app to:
-Temporarily serve a HTML form (to get information) on a randomized route/link (could be for a single request or for some time, say 10 minutes)
-Delete that route/link
-Start over
Here is the code I have so far:
const express = require('express')
const app = new express();
const fs = require('fs');
var link = Math.floor(Math.random() * (1000 - 0) + 0)
var changingroute = function (req, res, next) {
app.get('/' + link, function(req, res){
res.sendFile(__dirname + '/public/download.html');
});
setTimeout(endroute, 1000)
function endroute() {
app.delete('/' + link)
console.log('Route Closed: LocalHost:8080/', link);
}
link = Math.floor(Math.random() * (1000 - 0) + 0)
console.log('Route Opened: localhost:8080/',link);
next()
}
//app.use(changingroute);
const port = process.env.PORT || 8080;
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.renderFile(__dirname + '/public/index.html');
});
app.get('/' + link, function(req, res){
res.sendFile(__dirname + '/public/download.html', '/public/download.html', function(err, res) {
if (!err) {
res.setHeader('Location', pathname + '/');
}
});
});
app.listen(port, function() {
console.log('app running');
console.log(`Route Opened: http://localhost:8080/${link}`);
});
Explanation:
The current code doesn't do what I would like it to. As you can probably tell changingroute isn't used, the app.use is commented. What it did do was create new routes every time a request was made but it wouldn't close the route afterwards. Where I was last with this code was testing out something someone else did on SO but it kind of differed from what I am trying to do : Serving Temporary Files with NodeJs. With their code you can put up files to download but only once but that doesn't really translate to routes and pages as I understand. I get errors like "cannot replace header" if I try and change the page it displays, or if I try and close the route. I haven't seen any tutorials online that show how to make temporary routes, or maybe I haven't used the right keywords. If you have any advice on where I should look or what I should try please let me know. I would really appreciate it!

Accessing a functions from a js file thats in a public directory

I have a JS file in a folder called public, which also has my CSS file in it. I'm trying to access a function from the JS file (scripts.js), but am having no luck. I've followed this post (amongst others), but I am still getting an error of Error: Cannot find module './scripts.js'. If anyone can help me out, that would be great.
app.js
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var request = require("request");
var scripts = require("/scripts.js");
app.use(bodyParser.urlencoded({extended: true}));
app.set("view engine", "ejs");
app.use(express.static(__dirname + '/public'));
const apiUrl = "https://api.darksky.net/forecast/";
const apiKey = "XXX";
app.get('/', function(req, res){
res.render("index");
});
app.post('/results', function(req, res){
var lat = req.body.latitude;
var long = req.body.longitude;
request(apiUrl + apiKey + "/" + long + "," + lat, function(error, response, body){
if (!error && response.statusCode == 200) {
var data = JSON.parse(body);
var temperature = scripts.converter(data.currently.temperature)
res.render("results", {data: data, temperature: temperature})
} else {
console.log(response.body);
}
});
});
app.get('/results', function(req, res){
res.render("results");
});
app.listen(3000, function(){
console.log("Server has started");
})
scripts.js
module.converter = function(cel) {
var cel = (far - 32) * (5/9);
return cel;
}
exports.data = module;
The path to your module is wrong.
Try var scripts = require("./public/scripts.js"); instead.
You are loading /scripts.js, which is a scripts.js file located at your computers root. To load a file in the current directory, you would do ./scripts.js. In a directory above the current one, it would be ../scripts.js.
If the file is in a directory below the current directory, like in your case, it would be './directoryname/scripts.js'. directoryname being public in your case

Creating an Express JS 4.0 application with https on Openshift, including http redirection

Following another SO question, the latest I have been trying is (see ligatures.net):
self.ipaddress = process.env.OPENSHIFT_NODEJS_IP;
self.port = process.env.OPENSHIFT_NODEJS_PORT || 443;
if (typeof self.ipaddress === "undefined") {
self.ipaddress = "127.0.0.1";
};
...
self.app = express(); // 4.8.7
...
// Trusting Openshift proxy
self.app.enable('trust proxy');
// Http -> Https redirection middleware
self.app.use(function (req, res, next) {
if ( !req.secure() ) {
var tmp = 'https://' + process.env["DOMAIN_NAME"] + req.originalUrl;
console.log("Redirect to: " + tmp);
res.redirect(tmp);
} else {
next();
}
});
...
// Creating a http server
https.createServer(self.app).listen(self.port, self.ipaddress,
function(err) {
if (err) {
console.log("Node server error: " + err.toString());
} else {
console.log('%s: Node server started on %s:%d ...',
Date(Date.now() ), self.ipaddress, self.port);
}
});
In the Openshift logs, I get:
Property 'secure' of object # is not a function
This is the line: if ( !req.secure() ) {
The certificates are loaded in the console. The application starts successfully on port 8080.
Why am I getting this message and how should I create a secured Express 4.0 https application in OpenShift? Does anyone have operational code to share? Thanks!
UPDATE
I have updated the redirection as following:
// Http -> Https redirection middleware
self.app.use(function (req, res, next) {
if ( req.headers['x-forwarded-proto'] === 'http' ) {
var tmp = 'https://' + req.headers.host + req.originalUrl;
console.log("SERVER redirect to: " + tmp);
res.redirect(tmp);
} else {
var pt = req.protocol || "";
var ho = req.headers.host || "";
var ur = req.originalUrl || "";
console.log("\nProtocol: " + pt
+ "\nHost : " + ho
+ "\nUrl : " + ur);
var tmp = req.protocol + '://' + req.headers.host + req.originalUrl;
console.log("SERVER no redirect: " + tmp);
next();
}
I see a couple of the following from the console:
SERVER no redirect: http://undefined/
Protocol: http
Host :
Url : /
and my application still does not work. It looks like a bug to me.
I have opened an issue: https://bugzilla.redhat.com/show_bug.cgi?id=1138137
I am also behind Cloudflare, which may be part of the issue.
There were two issues:
i) If you are on Cloudflare's free plan, then it won't forward the SSL requests. If you disactivate Cloudflare (while keeping their DNS for example), then the SSL requests are forwarded to Openshift.
ii) For some unknown reason, some empty requests reach my application on Openshift when starting it, and when browsing pages later too:
req.path: /
req.protocol: http
req.originalUrl: /
req.secure: false
The code mentioned in Openshift's KB article cannot work well as is, for two reasons. First, req.path does not take query parameters into account. One should use req.originalUrl instead in Express 4.0.
Second instead of using self.app.get(r, redirectSec, self.routes[r]);, one should add the middleware with self.app.use in Express 4.0:
My HTTP to HTTPS forwarding code is now:
// Trusting Openshift proxy
self.app.enable('trust proxy');
// Http -> Https redirection middleware
self.app.use(function (req, res, next) {
if ( req.headers['x-forwarded-proto'] === 'http' ) {
var tmp = 'https://' + req.headers.host + req.originalUrl;
res.redirect(tmp);
} else {
return next();
}
}
});
All seems to work fine now.
req.secure is a property, not a function.
Try this bit of code from the help.openshift.com website:
function redirectSec(req, res, next) {
if (req.headers['x-forwarded-proto'] == 'http') {
res.redirect('https://' + req.headers.host + req.path);
} else {
return next();
}
}
Which can be found in this KB article: https://help.openshift.com/hc/en-us/articles/202398810-How-to-redirect-traffic-to-HTTPS-

Define pattern route for node js

I am using Node.js and express to make a web chat application. I have a question about routing.
My route is:
app.get("/", function( req, res ) {
res.sendfile( __dirname + "/index.html" );
});
And as far as I know it means all clients should go to http://www.example.com/index.html page to access the chat. ( maybe, not sure )
Is it possible to have a pattern URL like this:
app.get("/*", function( req, res ) {
res.sendfile( __dirname + "/*" );
});
so that any user can access to chat on any URL
In short: Something like facebook chat. which is accessible in all pages.
thanks in advance
Is it possible to have a pattern URL like this:
Yeah, Express supports exactly the route you listed. The documentation refers to it as an "unnamed wild-card."
// GET /foo -> (200) "foo"
// GET /baz/qux -> (200) "baz/qux"
app.get('/*', function (req, res) {
res.send(req.params[0]);
});
Though, for your example, Express/Connect includes a static() middleware for serving files by combining the URL path to a base directory:
app.use(express.static(__dirname));
Something like facebook chat. which is accessible in all pages.
This wouldn't necessarily have much of a relation to routing. Your application may need a route to gather a list of contacts or other persisted data, but the actual "chat" will be managed separately.
In general, it would depend on including common content in each page -- perhaps via a "layout" or "inheritance" if you're using views/templates -- to display the form for inputting message and an area to display chat history. Also, a fair amount of the "work" for the chat will have to be done client-side.
A quick example would be to serve the same file for multiple URLs:
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
app.get('/*', function (req, res) {
res.sendfile(__dirname + '/chat.html');
});
var chat = io
.of('/chat') // namespace
.on('connection', function (socket) {
socket.on('message', function (data) {
chat.emit('message', data);
});
});
server.listen(3000);
And, in that file:
<div id="chat-log"></div>
<form id="chat-send">
<input name="message">
<input type="submit" value="Send">
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
var chatForm = document.getElementById('chat-send');
var chatLog = document.getElementById('chat-log');
var chatSocket = io.connect('/chat');
chatSocket.on('message', function (data) {
chatLog
.appendChild(document.createElement('div'))
.appendChild(document.createTextNode(data.text));
});
chatForm.onsubmit = function () {
chatSocket.emit('message', {
text: chatForm.message.value
});
chatForm.message.value = '';
chatForm.message.focus();
return false;
};
</script>
Then, from any address (GET /, GET /foo, GET /bar/baz/qux), you can access chat.
You're probably going to want to use a url param like this:
app.get("/:chatter",function(req,res){
console.log("the chatter is",req.param('chatter'));
res.sendfile( __dirname + "/index.html" );
...
});

Setup file-system based routing in Node

I'm really a fan of the simplicity PHP offers in serving pages, everything is based on the filesystem. I want to do the same thing with Node. I tried one routing setup that worked like this for views, but broke my public folder:
//using express:
app.get('*', function(req, res) {
file = req.params[0].substr(1, req.params[0].length);
console.log('requesting: ' + file);
res.render(file, {locals: {
req: req,
params: req.query
}});
});
So...What's the best way to setup filesystem based/php style routing in Node?
I think that I build exactly what you are looking for. I use this to serve up .jade files, obviously you can tweak this for your use case.
var url = require('url');
var express = require('express');
var app = express.createServer();
var fs = require('fs');
app.set("view engine", "jade");
app.use(app.router);
app.use(express.static(__dirname + '/public'));
/**
* Generic "get" attempts to route to known JADE files.
* If no known JADE files, then we pass routing to next() (should be static).
*/
app.get('*', function(req, res, next) {
var pathname = url.parse(req.url).pathname.toLowerCase(); // make matching case insenstive
// First case: with no path name, render the default index.jade
if(!pathname) {
res.render('index', {});
}
// Second case: path ending in '/' points to a folder, use index.jade from that folder
else if (pathname === '/' || pathname.charAt(pathname.length-1) === '/' ){
res.render(__dirname + '/views' + pathname + 'index.jade', {});
}
// Third case: looks like an actual file, attempt to render
else {
// Attempt to find the referenced jade file and render that. Note 'views' is default path.
fs.stat( (__dirname + "/views" + pathname + '.jade'), function(err, stats){
// There was an error, the file does not exist pass control to the static handler
if(err || !stats) {
next();
}
// We found the file, render it.
else{
res.render(pathname.substring(1), {});
}
});
}
});
app.listen(port);
Note, there should be more app.use() statements there for handling cookies, parsing the body etc. Also, the second param of the render is always empty. You may want to fill this out with things like {layout: xyz} or generic variables that need to come in to the rendered pages.
You can use express.static()
For examples:
app.configure(function(){
app.use(express.static(__dirname + '/public'));
});
app.configure(function(){
app.use('/uploads', express.static(PATH_TO_UPLOAD_FOLDER));
});

Categories