Using Meteor.js, how can I serve an arbitrary HTTP response, eg. an image or PDF?
Example 1 - I need to generate PDF reports, which I cannot store in public/ or on a third-party server. Or, the report may be generated live in response to a HTTP GET.
Example 2 - If I have a url like:
/images/myimage.png
I would like to detect that request on the server, read the image from MongoDB, and serve it with the correct headers, so it is available to use with img tags, ie.
<img src="/images/myimage.png">
I do not want to store the images in the /public/ directory, so that I can have more control over exactly what is served and how it is permissioned.
Edit I was also able to get a basic example working using Iron Router.
ImageController = RouteController.extend({
run: function() {
var f = fs.readFileSync("/path/to/image.png");
var res = this.response;
res.writeHead(200, { "content-type": "image/png" });
res.write(f);
res.end();
}
});
Router.map(function() {
Router.route("images", {
path: "/images/image.png",
where: "server",
controller: ImageController // Note - cannot use string here - Iron Router has a dependency on window
});
});
You may write the response code as in any node app, using the middleware:
WebApp.connectHandlers.stack.splice (0, 0, {
route: '/path/to/the/file',
handle: function(req, res, next) {
res.writeHead(200, {
'Content-Type': ...ITEM TYPE... ,
});
res.write( ...ITEM DATA... );
res.end();
},
});
You can use filepicker. In filepicker the upload images is save in the bucket(cloud) and returns the url of that image. You can save the url in your mongo database. and when you want to use that image just use <img src="{{saveurl}}" > .
For more help see the documentation https://developers.inkfilepicker.com/docs/web/
Related
I'm a Node.js newb, so I'm not sure if it's possible to do what I'm trying to accomplish. Here is my configuration:
I have a Node.js server running on a Raspberry Pi on my home network. I have an HTML file on an external IP. I wish to render React components on this HTML file.
From what I've seen, people have used Node servers to display js on a local HTML file, so the path would normally look like this, assuming the directory is called 'dir':
const express = require('express');
const app = express();
// Static Routes
app.use('/dist', express.static(path.join(__dirname, 'dir')));
// App Route
app.get('/', (req, res, next) => res.sendFile(path.join(__dirname,
'index.html')));
Which, to my knowledge, transfers the HTML file found at the previously specified path. But where is this transferred to? Any way I can specify the path name based on an external IP + user + password, and file path?
Which, to my knowledge, transfers the HTML file found at the previously specified path. But where is this transferred to?
It transfers the file contents from disk to the client's network connection, when they request it (i.e. not when the server starts up).
Any way I can specify the path name based on an external IP + user + password, and file path?
Not with express.static. If you want to make your server serve an external page (proxying), you can do that: https://stackoverflow.com/a/10435819/7011366. Since you'll have access to the url & cookies, you can do whatever you like with the path/user/password.
app.post('/my_url', function(req, res) {
var options = {
host: MY_DOMAIN,
path: '/' + req.query.username,
method: 'GET',
};
var req = http.request(options, function(res) {
// etc...
// send response to client
}).on('error', function(e) {
// handle error...
}).end();
});
This above example makes a request to the external page every on every request. If you don't want that, you can store it in memory and only update it periodically.
let myHtml = "";
let fn = () => {
var options = {
host: MY_DOMAIN,
path: '/' + req.query.username,
method: 'GET',
};
var req = http.request(options, function(res) {
// etc...
// save response to myHtml as string
}).on('error', function(e) {
// handle error...
}).end();
};
setInterval(fn, 60000);
fn();
app.post('/my_url', function(req, res) {
res.end(myHtml);
});
You can not achieve it directly for the files stored on remote machine. Express static path works with local file system only.
Possible way for this could be, fetch file from the remote machine every time you get a new request. But no one does this.
Sorry, I tend to be a bad writer when I have not fully woken up, let me revise.
I am using expressjs with passportjs (local strategy) to manage my server and using connect-busboy to manage file uploading. I do not think passport will play a role in this.
Here is the server code for managing file uploads:
app.post('/upload', isLoggedIn, (req, res) => {
if(req.busboy){
req.pipe(req.busboy);
req.busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
if(mimetype.match(/^image\//)){
var root = path.join(__dirname, "../public/images/");
if(fs.existsSync(path.join(root, filename))){
var name = getUnique(path.join(root, filename));
} else {
var name = filename;
}
var ws = fs.createWriteStream(path.join(root, name), { flags: "a" });
file.pipe(ws);
}
});
}
});
As for my client page, it is used to change a JSON object which will get re-uploaded to the server as a configuration tool. When I upload a new image asynchronously I need to get the filename to update this JSON object while working on it. For uploading from the clients end I am using dropzonejs, which did not require any configuration on my part to work.
So, in summary I upload a number of images via dropzone asynchronously, busboy and fs on my server save the file, and I would like to get the filename returned to my javascript to modify the existing JSON object.
Edit solution:
Thanks to Elliot Blackburn for pointing me in the right direction.
By calling:
ws.on('close', () => {
res.send({filename: name});
});
after file.pipe(ws); to send the response back to the client. On the client side modify dropzone to handle the response like so:
dropzone.on('success', (file, res) => {
console.log(res);
});
Just send it in the normal http response. It'll depend what library you're using but most will allow you to trigger a normal req, res, next express call. From that you can access the file object, and return anything you want.
Something like:
req.send({filename: name}); // name is the filename var set earlier in the code.
Once you've finished editing the file and such, you can get the name and put it into that returned object and your client will receive that as object as the response which you can act upon.
I've got a simple node.js + Restify backend with standard CORS settings and this endpoint:
var file = '1,5,8,11,12,13,176,567,9483';
server.get('/download', function(req, res, next) {
res.set({"Content-Disposition": "attachment; filename='numbers.csv'"});
res.setHeader("Content-type", "text/csv");
res.send(file);
return next();
}, function(err) {
res.send(err);
});
What it's suppose to do is to is to create CSV file and return it.
It works great when I simply type in the endpoint address to web browser and hit enter. The file gets downloaded properly.
But when I try to do the same thing, but instead of using browser's address bar I use Restangular like that:
Restangular.one('download').get().then(function (res) {
console.log(res);
});
it just writes response to console, but no file is being downloaded.
Is there a way to do this using Restangular? Or maybe I need to use something else for this?
I am not sure if Restangular can do that, but I am using FileSaver script for stuff like that. Add Filesaver to your HTML head and then:
Restangular.one('download').get().then(function (res) {
var file = new Blob([res], { type: 'text/csv' });
saveAs(file, 'something.csv');
});
I am using node.js and the express framework to send a get request for an image by appending the image to the body using $('body').append('<img src="images/image.gif?34567">'). When I send the request, the console is logging GET /images/image.gif?34567 200 1.223 ms, but it won't run the functions inside of my router for the route to that image.
router.get('/images/*', function(req, res) {
console.log('Accessed image folder...')
var requestURL = url.parse(req.url,true);
//ATTEMPT to capture request
if(requestURL.pathname == '/images/image.gif') {
console.log("Fetching image...")
}
});
I was also trying to use the specific route: router.get('/images/image.gif', function(req, res) {, and tried following this example.
How can I make the GET router work when requesting a specific image inside of the images directory?
router.get('/images/:imageName', function(req, res) {
var image = req.params['imageName'];
res.header('Content-Type', "image/gif");
fs.readFile(image, 'utf8', function(err, data){
if(err){
res.end(404);
}
res.send(data)
});
});
Just grab the image name as a parameter, set the content type (you could also do this dynamically based on the requested file extension, for simplicity I only set it to gif), then do an async file load for the image name and return it.
If you are trying to view a image from node server, then you have to use express static . The following code might help you.
var express=require('express'),
app=express();
app.use("/pictures", lib.express.static("./assets/images"));
Here '/pictures' is the route to get image(e.g http:\localhost\pictures) and '/assets/images' is actual path foe image.
If you want to upload the image then you should use any upload module of node as per your requirement.
I have a image pic.jpeg which I have to display on browser.Here is snippet of code I have written.
var mimeTypes = {
'.js' : 'text/javascript',
'.css' : 'text/css',
'.gif' : 'image/gif',
'.jpeg': 'image/jpeg',
'.html': 'text/html'
};
contenttype = mimeTypes[path.extname(req.url)];
pathname = "." + req.url;
var stream = fs.createReadStream(pathname);
stream.on('error', function(error) {
res.writeHead(500);
res.end();
return;
});
res.setHeader('Content-Type', contenttype);
res.writeHead(200);
stream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
util.pump(stream, res, function(error) {
//Only called when the res is closed or an error occurs
console.log("Error:");
res.end();
return;
});
});
The above code works most of the time and the images displays like it should, but at times the image is missing.
You should not be serving static files through node.js. You should consider using Nginx or similar web server for the same.
Alternatively, you can use connect module to serve static files
var server = connect()
.use('/static', connect.static(__dirname + '/static'))
.use(router)
.listen(port);
Make a new directory named static and put all files in it, so you will be able to access them by /static/images/testimage.jpg
Rather than implementing static file serving yourself, why not use a library like Express? You can see that being used here: Express Static nodejs or see the API here: http://expressjs.com/api.html (search for "static"). It'll be a lot less code, and reliable.