Using directory (for images links etc) in Openshift (nodejs application) - node.js

I have a webpage that I have hosted using a node application on openshift. Its here
http://nodejs-volition.rhcloud.com/
My question is very simple (although I haven't found anyone else asking it). How do I refer to other files in the directory which contains index.html
For instance I would like to use an image that is in the directory in the index. My current html for the image is
<img src="$OPENSHIFT_REPO_DIR/images/1416870991752.jpg" alt="spark core">
I have also tried using "images/1416870991752.jpg". I have the same problem with linking to other html files in the directory?
What am I doing wrong? Please help?

As corey112358 alludes to below the key is in that to host using nodejs a server must be defined. My application already has a server file, so rather than creating a new server I must modify the existing one. I've done it successfully now, there were two changes to make to the server.js file.
The 1st change is modification of the cache. That should look like this...
self.zcache['index.html'] = fs.readFileSync('./index.html');
self.zcache['page2.html'] = fs.readFileSync('./page2.html');
self.zcache['sparkcoredark.jpg'] = fs.readFileSync('./sparkcoredark.jpg');
The first line was already included but the next two were added by me to include another html page and an image.
The second step is modify the self.createRoutes section of the server.js file as below (asciimo image is included by default).
self.createRoutes = function() {
self.routes = { };
self.routes['/asciimo'] = function(req, res) {
var link = "http://i.imgur.com/kmbjB.png";
res.send("<html><body><img src='" + link + "'></body></html>");
};
self.routes['/'] = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.send(self.cache_get('index.html') );
};
self.routes['/page2.html'] = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.send(self.cache_get('page2.html') );
};
self.routes['/sparkcoredark.jpg'] = function(req, res) {
res.setHeader('Content-Type', 'image/jpg');
res.send(self.cache_get('sparkcoredark.jpg') );
};
};
Hope that helps out anyone else struggling with this issue. Thanks to coreyfibonacci

Related

Unable to use res.send and res.download in Node/Express due to headers already being set

I am new to Node, and I am trying to make it so that when I go to 'localhost:1337/download/open' it renders a webpage, as well as download a file.. I understand that you can only set a header once (that is the error I am getting), but what is the easiest way to both render html AND download a file? Code below:
const express = require('express');
const app = express();
app.get('/download/open', function (req, res) {
let file = `${__dirname}/downloads/Open Tasks.csv`;
res.download(file);
res.send("words");
})
app.listen(1337, function (err) {
if (err) {
console.log(err)
return
}
console.log(`App running. listening on: http://localhost:1337`);
});
Error:
Error: Can't set headers after they are sent.
Thank you in advance.
I was able to figure out what I was trying to do. Instead of trying to render a whole new page AND download a file, I needed to dedicate a route to just a download through the use of an <a></a> tag.
For instance, if I have a webpage at 'http://localhost:1337' that has a link on it like:
Download Open Tasks
Download Open Tasks
Then in node.js I have a route for 'download/open' like so:
app.get('/download/open', function (req, res) {
let file = `${__dirname}/downloads/Open Tasks.csv`;
res.download(file);
})
It will not open a new page (like I thought it needed to) it will just download the file.
IMO, I would suggest you should do the following to achieve your goal:
render the HTML result for "GET http://localhost:1337/download/open"
In the HTML file /download/open, put AJAX block to invoke download file operation
(Download a file by jQuery.Ajax)
$(document).ready(function(){
//code to invoke download file....
});

Serve a file in a browser from a runtime directory using nodejs

In our application we store our reports in a user defined folders. User can add their own folders during runtime. Iam showing the history of those files in a web page. on clicking the file name i should show the file from the folder. How can i show the files from a non public directory.Since its given during runtime i havent added them as static dir to the express server.
One idea we tried was to use node-static-server and create a file server with the folder and serve the file. for each file we create this. it works fine but i get an error saying "port already in use". is there any better idea to do this? is this the right approach?
You can do this in NodeJS using a express.static:
const FS = require('fs')
const express = require('express')
const bp = require('body-parser')
const app = express()
function fileTest(req, res, next){
if (/\.|\/|\\/.test(req.params.file))
return res.sendStatus(400)
return next();
}
app.get(
'/static/:file',
fileTest,
function(req, res, next){
req.url = req.url.replace('/static','')
next()
},
express.static(
'./static',
{
fallthrough: false
}
)
)
app.post(
'/static/:file',
fileTest,
bp.text(),
function (req, res) {
FS.writeFile(
'./static/'+req.params.file,
req.body,
function (err) {
if(err)
return res.sendStatus(500)
return res.sendStatus(200)
}
)
}
)
app.listen(
1337
)
This is a simple example showing a server that will:
[POST]
Take a text body and load it into memory( pitfall: large bodies in memory )
Based on the URL, save it as a file in the static folder
[GET]
Search for a file
If found return file
The good news is that you can make the file and then request the file without restarting the server. Bad news is that this is a VERY SLOW server( comparatively to other options ).
As with all examples no good practices were followed, so be sure to adapt it to your needs.
Things to think about as you adopt it:
How do I allow people to save files to other folders?
How do I disallow people from saving files to other folders I don't want them to?
PROPER AUTHORIZATION

node.js: serve static web, match request url //*/web/ to file system /web/

I use node.js in a simple way to serve a static web.
...
app.use(express.static('./build'));
http.createServer(app).listen(port, ipaddress);
...
This serves the files 1:1 (with index.html as default resource), e.g.
//server/a.html -> ./build/a.html
//server/bbb/x.html -> ./build/bbb/x.html
//server/ccc/ -> ./build/index.html
But now, I need to be able to remove 'one level' of the request url, but it shall serve still the same web, e.g.
//server/aaaa/a.html -> ./build/a.html
//server/bbbb/a.html -> ./build/a.html
//server/xxxx/bbb/x.html -> ./build/bbb/x.html
//server/yyy/ccc/ -> ./build/ccc/index.html
So I need a wildcard matching in the request url. I tried this:
app.use('/\*', express.static('./build'));
http.createServer(app).listen(port, ipaddress);
But with no luck. No more page is accessible. What is wrong?
[Edited to show that the server should serve index.html as default resource]
Depending on your application, you might put express.static() on separate Router instances that are mounted on your app. For example:
var routerA = new express.Router();
// You could also reuse the same static file handler since they
// are all using the same root path
routerA.use(express.static('./build'));
// and other `routerA` route handlers ...
var routerB = new express.Router();
routerB.use(express.static('./build'));
// and other `routerB` route handlers ...
// etc.
However if you don't have your application broken up like this already, you could also specify multiple routes like:
app.use(['aaaa', 'bbbb', 'xxxx'], express.static('./build'));
Or if nothing else, you could just use a custom middleware, calling the static file handler manually (although this is kind of a hack, as it was what separate, mounted Routers were designed to help solve):
var staticHandler = express.static('./build');
app.use(function(req, res, next) {
var m = /^\/[^/]+(\/.+)$/.exec(req.url);
if (m) {
// Temporarily override the `req.url` so that the path
// concatenation will happen correctly
var oldUrl = req.url;
req.url = m[1];
staticHandler(req, res, function(err) {
// Reverting the to the original `req.url` allows
// route handlers to match the request if a file
// was not found
req.url = oldUrl;
next(err);
});
} else
next();
});
app.get('/aaa/foo', function(req, res) {
res.end('hello from /aaa/foo!');
});
My final solution is:
// serve all files from ./web directory regardless of first element in url
app.get('/:leveltoremove/*', function(req, res) {
var path = req.params[0] ? req.params[0] : 'index.html';
res.sendfile(path, {root: './web'});
});
http.createServer(app).listen(port, ipaddress);

Expressjs file download - not downloading

I can't seem to get my "download file" feature working using Expressjs.
//DOWNLOAD FILE
router.get('/snippets/download', function (req, res) {
res.attachment("untitled.js");
res.send("here is some javascript");
});
If I access this route in my browser the file downloads to my computer but not if I use an Angularjs request to the route.
Am I missing something?
You can use res.download. Refer documentation here: http://expressjs.com/4x/api.html
Eg:
//DOWNLOAD FILE
router.post('/snippets/download', function (req, res) {
res.download(req.body.filename, req.body.text);
});
See if this helps.
The res.download() method need a file's full path ( which could be different in windows and linux with different seperator ).
And the 2nd param of res.download(localName, downloadPromptName ) should be able to modify the filename that user see (different from the file in your server's directory), but it seems that does not work in my environment.
So I recommend you to use res.sendFile(fullNameInServer ,options) where you can modify the downloaded filename in options.
var root = getDownloadRoot(req);
var options = {
root: getDownloadRoot(req),
headers: {
"content": "text/html;charset=utf-8",
"Content-Type": "application/octet-stream",
"Expires":"0",
"Cache-Control": "must-revalidate, post-check=0, pre-check=0",
"content-disposition": "attachment;filename=" + urlencode(downloadFilename)
}
};
res.sendFile( tempFileName ,options);
urlencode should be required to encode filename then you can use filename other than english.
before call download file , you need to write the file physically in a temp folder,
the getDownloadRoot() method give you the temp folder location in runtime which does not vary when you change the path to run the app.
here is the function getDownloadRoot()
function getDownloadRoot(req){
var path = require('path');
var sep = path.sep;
var parentPath = path.dirname(req.settings.views);
var ret = parentPath.concat(sep + tempFileFolder);
return ret;
}
For now I have no way other than using app.setting (that app is declared in app.js) to get the application folder during runtime. So I made a litte 'middleware' to transport the value with req object as following.
In app.js:
app.use(function(req, res, next) {
req.settings = app.settings;
next();
});
tempFileFolder is a folder that you can name it yourself.
sep is the folder seperator ( \ in windows and / in linux )
Also you need to watch the folder permission settings when running in linux.
This combination works perfectly in my environment (with angularjs)

node-static is sending .aspx extension content as download

I'm not sure how to server .aspx files with node-static.
I am using node-static to serve .html .js .css, and images (works as expected),
but when I request test.aspx (a file in the public folder) it prompts the browser(s) (Chrome and FF) to download as a file, when I want it to be treated as HTML (text/html).
node code is really basic
var node_static = require('node-static');
var node_static_file = new(node_static.Server)('./public');
var http = require('http');
var server = http.createServer(function(req, res) {
// static file server
req.addListener('end', function () {
node_static_file.serve(req, res, function (err, result) {
if (err) { // There was an error serving the file
res.writeHead(err.status, err.headers);
res.write("Error: Page " + err.message + " (" + err.status + ")");
res.end();
}
});
});
}).listen(80);
Thanks,
This is due to node-static not knowing what kind of file aspx is. Currently it looks like there is no default way to extend the mine types of node-static.
You can see in the code that if the mime type does not exist that Content-Type is set to application/octet-stream. A quick hack would to go into your node_modules directory and edit the lib/node-static/mime.js file and include a aspx extension and give it a content type of text/html.

Resources