I have an img tag in my html that requests the image from nodejs server. In my server js file I have below code to send image response but I observed data is not rendered on client side. Any suggestions?
const getFile = (filePath) => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, (error, data) => {
if (!error) {
resolve(data);
} // enter code here
else reject(error);
});
});
};
getFile(test.jpg).then((data) => {
response.statusCode = "200";
response.setHeader("Content-Type", "image/jpg");
response.end(data, "base64"); // Also tried response.end(data, "binary")
})
.catch(error => console.log(error));
Is this an Express application? If so, your best bet is to use the static middleware. Put all your static (binary) files in one folder, expose it with the static middleware, and load it that way.
Instead of fs.readFile, using fs.createReadStream and piping the chunks worked for images.
let frstream = fs.createReadStream(url);
response.statusCode = "200";
response.setHeader("Content-Type", "image/jpeg");
frstream.pipe(response);
Related
I tried following these instruction but couldn't get the URI decoded. how can I go about this?
When I enter a city like http://localhost:5000/weather?weatherCity=Malmö the URL changes to this http://localhost:5000/weather?weatherCity=Malm%C3%B6,
How can I decode the last part and what am I doing wrong?
app.get('/weather', (req, res) => {
const weatherCity = (req.query.weatherCity)
let decodeURI = decodeURIComponent(weatherCity) //<------- trying to decode the query
request(weatherURL(decodeURI), function (error, response, body) {
if (error) {
throw error
}
const data = JSON.parse(body)
return res.send(data)
});
})
function weatherURL(weatherCity){
return `https://api.openweathermap.org/data/2.5/weather?q=${weatherCity}&units=metric&appid=${process.env.APIKEY}&lang=en`
}
This is probably what you need:
app.get('/weather', (req, res) => {
const weatherCity = req.query.weatherCity;
request(weatherURL(weatherCity), function (error, response, body) {
if (error) {
throw error
}
const data = JSON.parse(body)
return res.send(data)
});
})
function weatherURL(weatherCity){
return `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(weatherCity)}&units=metric&appid=${process.env.APIKEY}&lang=en`
}
There should be no need to decode req.query.weatherCity because express does this automatically.
You do need to encode weatherCity before building a URL with it. URL query parameters should be URL encoded.
Consider using something other than request because it is deprecated and doesn't support promises. node-fetch and axios, among others, are good choices.
How do I create a file in express and node on my server and then download it to my client. I am using NextJS for my frontend and backend. I am confused on how I would download the file on the front end after the file is created on the root of the server folder. Since I am using React for my frontend whenever I try to visit that filepath it tries to take me to a page instead of the file
Here is what I have in my express route in node
var xls = json2xls(json, {
fields
});
// If there isn't a folder called /temp in the
// root folder it creates one
if (!fs.existsSync('./temp')) {
fs.mkdirSync('./temp');
}
const fileName = `temp/${req.user.first_name}${req.body._id + Date.now()}.xlsx`
// fs.writeFileSync(fileName, xls, 'binary');
fs.writeFile(fileName, xls, 'binary', function (err, result) {
if (err) {
return console.log(err);
}
console.log(result, 'this is result')
});
Here is what I have on my frontend
axios.post('api/download',payload)
.then(res => {
const link = document.createElement('a');
link.href = res.data.url;
link.download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch(err => {
throw err
})
Can you make request with GET on api, and.
Make request with GET.
Make temp directory to be static resources directory:
app.use(express.static('temp')); // app is your express instance.
// Maybe you have to correct temp's path
Response the post request with file url data
fs.writeFile(fileName, xls, 'binary', function (err, result) {
if (err) {
return console.log(err);
res.status(500).json({err});
}
console.log(result, 'this is result');
res.json({url: 'http://localhost:8080/temp/' + fileName}); // res is response object of you router handler.
// Maybe you have correct the server address
});
On other way, you can send the xls binary direct to client, in the client you create a BLOB object from the response, then create download link for the blob object.
My API end point returns an excel file streamed from S3. It works on the local but when testing on API gateway the file is corrupted. Here is my API code:
const downloadContentFromS3 = async function(bucket, file) {
return new Promise((resolve, reject) => {
streamFileFromS3(bucket, file, (error, s3buffer) => {
if (error) return reject(error);
return resolve(s3buffer);
});
});
};
const streamFileFromS3 = async function(bucket, fileName, callback) {
const params = {
Bucket: bucket,
Key: fileName,
};
const buffers = [];
const stream = s3.getObject(params).createReadStream();
stream.on('data', data => buffers.push(data));
stream.on('end', () => callback(null, Buffer.concat(buffers)));
stream.on('error', error => callback(error));
};
downloadExcelFile: async (req, res) => {
try {
const fileName = 'myFilename';
const workbook = await downloadContentFromS3(
'bucket-name'
fileName
);
const workbook = xlsx.read(buffer);
res.setHeader('Content-disposition', `attachment; filename=${fileName}`);
res.setHeader(
'Content-type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
);
const wbout = xlsx.write(workbook, { bookType: 'xlsx', type: 'buffer' });
res.status(200).send(Buffer.from(wbout));
} catch (error) {
throw new OriolaError(error.message);
}
},
What I have tried so far: Setup the binary media types as shown in the picture:
In addition tried to set the RESPONSE HEADER to Content-Type and Content-Disposition but to no avail. The problem seems to persist. Any ideas and help is appreciated.
EDIT: I have also tried to set binary type */* in the settings but this does not help as well.
API Gateway and Lambda send files between themselves as base64. This is regardless of whether you set a binary media type on API Gateway, as API Gateway does the conversion between base64 and binary.
S3 getObject gets a binary file, but that is a moot point for your problem, as you are still creating a binary file with xlsx.
What you are currently doing is sending binary data untransformed as base64 data.
All you need to do is return the file as a base64 buffer instead of a binary one.
So
res.status(200).send(Buffer.from(wbout));
becomes
res.status(200).send(Buffer.from(wbout).toString('base64'));
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html
So either
setup passthrough behaviour and send binary response body from your function as you are already doing,
or set the contentHandling property of the IntegrationResponse resource to CONVERT_TO_BINARY in addition to binaryMediaTypes setting already done and then send base64 response body.
I'm trying to download an image from my server using request.
I've managed to download something but i get more data than the image.
function _download(uri, save_as, destination) {
let options = {
uri: uri,
timeout: 100000,
followAllRedirects: true
};
return new Promise(( _resolve,_reject) => {
let ext, filename, bar, total, downloaded, req;
req = request(options).on('response', (resp) => {
if (resp.statusCode === 200){
ext = _getFileType(resp.headers['content-type']);
filename = destination+'/'+save_as+ext;
var stream = fs.createWriteStream(filename)
resp.pipe(stream).on('error',function(err){
_reject(err);
}).on('finish',function(){
_resolve(filename);
});
} else {
_reject("unable to download image %s",uri);
}
}).on('error', function(err) {
console.log(err)
_reject(err);
})
});
}
My original url is in form of https://www.test.com/image/original/12345, my server than redirects with a 301 status to my s3 bucket where image is stored.
Unfortunately due to the url of the image i have to wait that for the response header content type to determinate what kind of image it's and use it to pipe the image.
Everything works quite as expected... but i get more data than what is stored in s3.
Does anyone have any suggestion ?
please refer to the link below
var fs = require('fs'),
request = require('request');
var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
download('https://www.google.com/images/srpr/logo3w.png', 'google.png', function(){
console.log('done');
});
please visit this link
And this link also
Im struggling to find material on this
I have a rest API, written in node.js, that uses mongoDB.
I want users to be able to upload images (profile pictures) and have them saved on the server (in mongoDB).
A few questions, Ive seen it is recommended to use GridFS, is this the best solution?
How do i send these files? Ive seen res.sendFile, but again is this the best solution?
If anyone has any material they can link me I would be appreciative
thanks
You won't be able to get the file object on the server directly. To get file object on the server, use connect-multiparty middleware. This will allow you to access the file on the server.
var multipart = require('connect-multiparty');
var multipartmiddleware = multipart();
var mv = require('mv');
var path = require('path');
app.post("/URL",multipartmiddleware,function(req,res){
var uploadedImage = req.files.file;
for (var i = 0; i < uploadedImage.length; i++) {
var tempPath = uploadedImage[i].path;
var targetPath = path.join(__dirname ,"../../../img/Ads/" + i + uploadedImage[i].name);
mv(tempPath, targetPath, function (err) {
if (err) { throw err; }
});
}
})
Use file system
Generally in any database you store the image location in the data as a string that tells the application where the image is stored on the file system.
Unless your database needs to be portable as a single unit, the storing of images inside of the database as binary objects generally adds unnecessary size and complexity to your database.
-Michael Stearne
In MongoDB, use GridFS for storing files larger than 16 MB.
- Mongo Documentation
Therefore unless your images will be over 16 MB, you should either store the file on a CDN (preferable) or the server's own file system and save its URL to user's document on the database.
Local file system implementation
This method uses Busboy to parse the photo upload.
in relevant html file:
<input type="file" title="Choose a file to upload" accept="image/*" autofocus="1">
Handler function for your photo upload route in server file (you will need to fill in the variables that apply to you and require the necessary modules):
function photoUploadHandlerFunction (req, res) {
var busboy = new Busboy({ headers: req.headers })
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
const saveToDir = path.join(__dirname, uploadsPath, user.id)
const saveToFile = path.join(saveToDir, filename)
const pathToFile = path.join(uploadsPath, user.id, filename)
const writeStream = fs.createWriteStream(saveToFile)
createDirIfNotExist(saveToDir)
.then(pipeUploadToDisk(file, writeStream))
.then(findUserAndUpdateProfilePic(user, pathToFile))
.catch((err) => {
res.writeHead(500)
res.end(`Server broke its promise ${err}`)
})
})
busboy.on('finish', function () {
res.writeHead(200, { 'Connection': 'close' })
res.end("That's all folks!")
})
return req.pipe(busboy)
}
Where the promise functions createDirIfNotExist and pipeUploadToDisk could look like this:
function createDirIfNotExist (directory, callback) {
return new Promise(function (resolve, reject) {
fs.stat(directory, function (err, stats) {
// Check if error defined and the error code is "not exists"
if (err) {
if (err.code === 'ENOENT') {
fs.mkdir(directory, (err) => {
if (err) reject(err)
resolve('made folder')
})
} else {
// just in case there was a different error:
reject(err)
}
} else {
resolve('folder already existed')
}
})
})
}
function pipeUploadToDisk (file, writeStream) {
return new Promise((resolve, reject) => {
const fileWriteStream = file.pipe(writeStream)
fileWriteStream.on('finish', function () {
resolve('file written to file system')
})
fileWriteStream.on('error', function () {
reject('write to file system failed')
})
})
}
To answer your question 'How do I send these files?', I would need to know where to (MongoDB, to the client...). If you mean to the client, you could serve the static folder where they are saved.
If you still want to learn about implementing GridFs tutorialspoint have a good tutorial
More material
Good tutorial on handling form uploads
Tutorial using the node-formidable module
If you're using the mongoose odm you can use the mongoose-crate module and send the file wherever for storage.
Also, this is a good case for shared object storage like AWS S3 or Azure blob storage. If you are running a distributed setup in something like AWS, you usually don't want to store photos on the local server.
Store the url or key name in the database that points to the S3 object. This also integrates with CloudFront CDN pretty easily.
As suggested before. MultiPart for the actual upload.