I am using gridfs and mongoDB to store images in chunks. And whenever a user requests my server just sends a streamlined image file in response by piping.
Currently my code looks like this :
const download = async (req, res)=>{
try{
const fileName = req.params.name
await mongoClient.connect();
const database = mongoClient.db(dbConfig.database)
const bucket = new GridFsBucket(database, { // required for important methods like openDownloadStream
bucketName:dbConfig.imgBucket
})
const downloadStream = bucket.openDownloadStreamByName(fileName);
downloadStream.pipe(res) // it only displays an jpg/png image
// res.render("image") , I want to render this ejs page with a image in it and with some static content in it. I want to stream image
} catch(err){
res.status(501).render("error",{error: err})
}}
My output looks like :
my code output
It only renders a jpg file, like how above link is working see it.
but rather what i want to do is to get image from response object and render it with my other html elements.
Looks like you're trying to do too much at once.
You need to de-couple the desired streaming image from the initial rendering of your template. Include an image tag in your tempalte with a distinct api from which the image will stream, and the result will look something like your example.
Say your image is called test.png, your server index.js, and your ejs teplate index.ejs. The template (for the sake of your question) can be very simple: index.ejs-->
<h1> stream that image below! </h1>
<image src="/image" hieght="200px" width="200px";/>
Notice the src of this image - this will hit a distinct api on your backend that will stream the image.
The server index.js will look like this -->
var exp = require("express");
var fs = require("fs");
var app = exp();
app.set("view engine", "ejs");
app.get("/image", (req, res) => {
const streamReadFile = fs.createReadStream("test.png");
streamReadFile.pipe(res);
});
app.get("/", (req, res) => {
res.render("index");
});
app.listen(8080, () => {
console.log("listening on *:8080");
});
Notice here at the home route you render the template as
app.get("/", (req, res) => {
res.render("index");
});
The src in the image of your template then makes a request back to the server, hitting the /image route which will stream the desired image to your html
app.get("/image", (req, res) => {
const streamReadFile = fs.createReadStream("test.png");
streamReadFile.pipe(res);
});
Here's a working demo of the example above, where your image is streamed to an ejs template.
Related
I want to realize uploading files for my users. I use CKEDITOR 5 in my react project. Back-end on nodeJS.
So, i can upload file, can get its Url, but, can't display one in VIEW page.
//my server code
const express = require('express');
//for uploading i use this module
const multiparty = require('connect-multiparty');
const multipartyMiddleware = multiparty({uploadDir: '/var/www/group0384.ru/public_html/server/uploads'}) //here is whole path to my upload folder on server
const app = express();
const port = 3555;
const path = require('path');
const moment = require('moment');
const fs = require('fs');
//so, here i have route /upload, which is indicated in configuration of ckeditor as route to send pictures
app.use(express.static("uploaded"));
app.post('/upload', multipartyMiddleware, (req, res) => {
var TempFile = req.files.upload;
var TempPathfile = TempFile.path;
const targetPathUrl = path.join(__dirname,"./uploaded/"+TempFile.name);
if(path.extname(TempFile.originalFilename).toLowerCase() === ".png" || ".jpg"){
fs.rename(TempPathfile, targetPathUrl, err =>{
res.status(200).json({
uploaded: true,
url: `${__dirname}/uploaded/${TempFile.originalFilename}`
}); // this path is the same as in 5th row (except folder, here it change, but it's no matter)
if(err) return console.log(err);
})
}
})
//------------CKEDITOR CODE---//
<CKEditor
editor={ClassicEditor}
data={this.state.data}
onChange={(event, editor) => {
this.setState({
data: editor.getData(),
});
}}
config={
{
ckfinder: {
uploadUrl: '/upload'
} // here, /upload - the route to send pictures
}
}
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
On my VIEW page, i getting this
screenshot
So, i've tried to change paths, but still couldn't get the picture.
please explain why I can't just get and output a file that is already uploaded on my own server
P.S. Sorry for my english
It seems from the screenshot that you are getting the absolute path to the image, if you want to show the image on the client-side and you are sure the image is saved on your server, you have to send it back as a public URL address of your image!
example: "http://example.com/images/image1.png"
Thank you all for answers, i resolved the problem.
In this part i change url for uploaded images
res.status(200).json({
uploaded: true,
url: `/files/${TempFile.originalFilename}`
});
Then, i created route with this url
app.get('/files/:url(*)', (req, res) => {
console.log(req.params.url)
res.sendFile(path.resolve(__dirname + '/uploaded/' + req.params.url))
})
And it works!
I'm trying to weather Api app using node, express and Axios in backend part without using any framework like Angular or react.
I have 3 main file for my codes.
index.html
customer.js (for front end part)
server.js (for backend part)
My backend part like below;
const express = require('express');
const app = express();
const axios = require('axios').default;
API_KEY = "***";
const PORT =3000;
// app.use("/static", express.static(__dirname + '/customer'));
app.get('/', (req, res) =>{
axios
.get(`http://api.openweathermap.org/data/2.5/forecast?q=amsterdam&appid=${API_KEY}`)
.then(resp => {
let weatherDetail = resp.data;
console.log('a single country details: ', weatherDetail);
res.send(weatherDetail);
})
.catch(err => console.log(err));
});
app.listen(PORT, () => console.log(`My app listening on port ${PORT}! `));
When I write localhost:3000 on browser, I can see the weather api's data. However I want to see html file with functions in customer.js and api's data. Therefore I tried to write res.sendFile((__dirname + '/index.html')); inside app.get('/', (req, res)) function. However, in this situation I can see only html page without getting data from backend.
How can I call data getting from backend part in frontend part inside customer.js file?
My codes in customer.js like below (but I'm not sure if I use axios agan inside this file)
const apiCall = cityName => {
let apiKey = "***";
let apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${apiKey}&units=metric`
axios
.get(apiUrl)
.then(getWeather)
.catch(err => {
console.log(err);
err.response.status === 404 ? alert(`The country ${cityName} doesn't exist.`) : alert('Server error! Sorry.');
});
};
apiCall(amsterdam)
function getWeather (response) {
let city = document.querySelector("#city");
city.innerHTML = response.data.name;
.
.
.
.
}
I would recommend to use a templating engine like handlebars or ejs.There are tons of examples for it, and sending data from backend to frontend becomes a piece of cake when using any templating engine. my personal favourite is handlebars because of its simple syntax.
It is advisable not to use document.querySelector if you're using Angular or React. React/Angular will have the browser repaint the DOM by making updates in the "root" div element of the index.html file whenever there is new data available to update.
Also, why do you want to send a HTML file? You could have a route in Node like below
route.get('/weather', (req, res) => {
// do your api call with axios to get weather data
res.json(weatherData);
});
from your front-end you could make an API call to '/weather' route and consume the JSON data
axios.get('baseUrl/weather').then(res=>{
console.log("weather data", res);
}).catch(...);
You could also fetch weather data directly from front-end like above.
I have some code written that takes a single image file from index.html through an HTML form, adds a border to it using the gm module and saves it on the server. Now I'm trying to find a way to display it back to the user, preferably on the same page it was uploaded.
const express = require('express');
const app = express();
const multer = require('multer');
const gm = require('gm').subClass({imageMagick: true});
app.use(express.static(__dirname + '/public'))
app.use(express.static(__dirname + '/output'))
const upload = multer({
dest: 'temp/'
});
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
app.post('/', upload.single('file-to-upload'), (req, res) => {
var temp = req.file['path'];
var output = __dirname + '/output/' + req.file['filename'] + '.png'
console.log(req.file)
gm(temp)
.setFormat('png')
.resizeExact(512,512)
.composite(__dirname + '/masks/border.png')
.write(temp, function() {
gm(512, 512, 'none')
.fill(temp)
.drawCircle(256, 256, 256, 0)
.write(output, function(err) {
console.log(err || 'done');
});
});
});
app.listen(3000);
Right now your Express route never responds, it leaves the connection to the browser hanging. The key here is to respond with an HTML document. The laziest way to do that is (continuing at the end of your function):
.write(output, function(err) {
console.log(err || 'done');
return res.send(`
<title>My Image Is Neat!</title>
<h1>My Image Is Neat!</h1>
<img src="/${req.file['filename'] + '.png'}" />
`);
});
/${req.file['filename'] + '.png'} works because your use of express.static is mapping the /output folder into the root. You might want to add /uploads as the first argument so that the paths begin with /uploads and are less easily confused with other things.
As for including it in the page from which they uploaded it, you can write a function to send a similar backticked string for the original form, or you can get a little less lazy and use a templating language like Pug or Nunjucks to break these out to separate files.
Your approach so far implies you are not creating a single-page application with React, Vue, etc. but rather building old-school HTML forms. But if your real goals involve those frameworks you will need to change your approach to create an API rather than render pages.
I would like to serve up a ReactJS Single Page App from a nodeJS server and pass up some JSON data at the same time.
I have user credentials and some other user specific data that i would like pre-populated into my page and avoid making multiple round trips to the server.
How do i pass a JSON object to the client at request time and have it available to my React app
var path = require('path');
const express = require('express');
const app = express();
const port = process.env.PORT;
app.use(express.static('dist'));
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, '../../dist/index.html'));
});
app.listen(port, () => console.log(`Running on port ${port}.`));
I can suggest you add a script tag into your index.html file. Like below
<script>
window._DATA_={ key: 'value', .....}
</script>
Now in your react application, use the key window._DATA_ to get the data that you sent from the server. In this approach, the problem is that you can't send dynamic data.
To achieve that you may need to use the template libraries. For example pug, nunjucks, ejs, etc.
Below is the example of using pug.
Your express route will look like this.
app.get('/*', function(req, res) {
res.render('index', data);
});
// End of your pug file looks like
...
...
script.
var window._DATA_= !{JSON.stringify(data)}
If you want to add scripts files dynamically then you can use html-webpack-pug-plugin.
For more info
https://www.npmjs.com/package/html-webpack-pug-plugin
I'm getting started with firebase, firebase functions are returning a string which is a html format. I couldn't find any way to reply with html file which is a public html file or at least redirect to it(without rewrites).
I'm new nodejs and stuff. I googled and found few other modules/frameworks are using this.
var fs = require('fs');
pp.get('/test', function(req, res, next) {
var html = fs.readFileSync('./html/test.html', 'utf8')
res.render('test', { html: html })
// or res.send(html)
})
I think you just have to send html path with "sendFile" method like this :
pp.get('/test', function(req, res, next) {
res.sendFile('html/test.html');
});
Hope it helps.
I ended up with this solution and works fine.
const functions = require('firebase-functions');
var path = require('path');
var site_root = path.resolve(__dirname+'/..');
exports.blog = functions.https.onRequest((req, res) => {
res.status(200).sendFile(site_root+'/app/index.html')
});
You can't just use render out the box, render works with different types of renderers (or at minimum needs configured via the view engine).
In your case however, if the file is static and you know the path then you can use res.sendFile
// configure static path (not necessary to render the page but useful if you have other static assets)
pp.use(express.static(path.resolve(__dirname, 'html'));
// serve HTML
pp.get('/test', (req, res) => res.sendFile(path.resolve(__dirname, 'html', 'test.html')));