I'm trying to create and then send zip file to client. I know how to create it but I've got a problem with send it to client. I tried many ways.
I'm sending POST request from Client and as response I want to send a file.
This is my server-site example code
var Zip = require('node-zip');
router.post('/generator', function(req, res, next) {
var zip = new Zip;
zip.file('hello.txt', 'Hello, World!');
var options = {base64: false, compression:'DEFLATE'};
fs.writeFile('test1.zip', zip.generate(options), 'binary', function (error) {
console.log('wrote test1.zip', error);
});
res.setHeader('Content-disposition', 'attachment; filename=test1.zip');
res.download('test1.zip');
}
});
I also tried something like this:
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);
var filestream = fs.createReadStream(file);
filestream.pipe(res);
I tried to use such libraries as:
node-zip
archiver
Can anyone explain me how to do that ?
This module works fine too: https://www.npmjs.com/package/adm-zip
Example without creating temporary zip file in server:
var AdmZip = require('adm-zip');
router.get('/zipFilesAndSend', function(req, res) {
var zip = new AdmZip();
// add local file
zip.addLocalFile("./uploads/29/0046.xml");
// get everything as a buffer
var zipFileContents = zip.toBuffer();
const fileName = 'uploads.zip';
const fileType = 'application/zip';
res.writeHead(200, {
'Content-Disposition': `attachment; filename="${fileName}"`,
'Content-Type': fileType,
})
return res.end(zipFileContents);
});
Try this express-easy-zip npm package to generate a zip file from a local folder path and send it as a download to the client.
var zip = require('express-easy-zip');
var app = require('express')();
app.use(zip());
app.get('my-route/zip', async function(req, res) {
var dirPath = __dirname + "/uploads";
await res.zip({
files: [{
path: dirPath,
name: 'Package'
}],
filename: 'Package.zip'
});
});
I haven't worked with node-zip or archiver before (I usually just use the built-in zlib module), but one thing I noticed right away is that you should place res.download inside the callback of writeFile. That way it will only send the file once it has been fully written to disk.
fs.writeFile('test1.zip', zip.generate(options), 'binary', function (error) {
res.download('test1.zip');
});
I hope this solution works for you, if it doesn't feel free to comment.
Also, I think res.download sets the Content-disposition header for you, you don't need to set it manually. Not 100% sure on that one though.
Above solutions work.(above solutions generate zip and send it to frontend as data in response. In order to make it as downloadable following code will work) I was using express-zip. It is compressing files and sending data to frontend from backend(node). But in frontend I was getting only data in response. In my case I want user can be able to download the zip which sent by server. To solve this I followed following approach. For generating download window in browser i used downloadjs (we can follow another approach but i find this easy)
Front-End
const download = require('downloadjs')
return axios({
url:process.env.API_HOST+'/getuploadedfiles',
method:'get',
headers:{
'Content-Type': 'multipart/form-data',
withCredentials:true,
},
responseType:'arraybuffer' // If we don't mention we can't get data in desired format
})
.then(async response => {
console.log("got al files in api ");
let blob = await new Blob([response.data], { type: 'application/zip' }) //It is optional
download(response.data,"attachement.zip","application/zip") //this is third party it will prompt download window in browser.
return response.data;
})
Backe-End
const zip = require('express-zip');
app.use('/getuploadedfiles',function(req,res){
res.zip([
{path:'/path/to/file/file2.PNG',name:'bond.png'},
{path:'/path/to/file/file1.PNG',name:'james.png'}
])
Related
I'm developing a web application using nodejs server-side. I'm trying to send pdf files from client to server.
Client:
var files = new FormData();
var count = 0;
$('#tableSlideId tr').each(function() {
var inputForm = $(this).find("th:first").children();
file = inputForm[0].files[0];
files.append((count++).toString(),file);
});
$.ajax({
type: "POST",
url: "/sendFiles",
data: files,
contentType: false,
processData: false,
}).done(function(err){
var text ="";
if(err) {
text = "Upload FAILED! Retry ...";
} else {
text = "Upload SUCCES!";
}
alert(text);
});
I think the client side is ok, infact if I use this loop:
for(var p of files)
console.log(p);
I correctly visualize all the elements that I want to send to the server.
Server:
app.post('/sendFiles', function(req,res) {
console.log("--->",req.body);
res.end();
});
Now in the server I have no idea how to visualize the data that I send, infact req.body is empty.
I don't know if this is the right way but my goal is to load some pdf files form the client, send to the server and after store them in a mySql dmbs.
Thank you.
Use express-formidable module. install 'express-formidable' by the running command
npm install express-formidable --save
a simple example is as follows from github
const express = require('express');
const formidable = require('express-formidable');
var app = express();
app.use(formidable());
app.post('/upload', (req, res) => {
//req.fields contains non-file fields
//req.files contains files
console.log(req.fields);
console.log(req.files);
});
Hope this helps!
Edit, from here -
app.post('/submit-form', (req, res) => {
new formidable.IncomingForm().parse(req, (err, fields, files) => {
if (err) {
console.error('Error', err)
throw err
}
console.log('Fields', fields)
console.log('Files', files)
files.map(file => {
console.log(file)
})
})
})
I think you need some middleware to accept the multipart formdata in the server side. Multer is a good option.
You can use
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
and then update your server side to handle the upload:
app.post('/sendFiles', upload.array('files', maxCount), function(req,res)
I am trying to use the fastify-multer plugin to upload files to the server and I am able to successfully get the images uploaded to the folder.
The problem is my app crashes.
I used the fastify-cli generated structure and I am running it as a standalone server as mentioned in the README.md here.
I am writing it as a fastify plugin.
"use strict";
const fp = require("fastify-plugin");
module.exports = fp(function(fastify, opts, next) {
fastify.decorate("uploadImage", function(request) {
const path = require("path");
const multer = require("fastify-multer");
var storage = multer.diskStorage({
destination: path.join(path.join(__dirname + "/uploads/")),
filename: function(request, file, cb) {
cb(null, file.originalname);
}
});
var upload = multer({ storage }).single("myImage");
upload(request, function(err) {
if (err) {
console.log(err);
} else {
console.log("Saved...");
return { saved: true };
}
});
});
next();
});
And here is the error I get :
Hi looked into your issue. You are using fastify-multer in the wrong way.
Invoking multer({ storage }).single("myImage") you are creating a fastify's preHandler hook that accepts 3 specific parameters. You can find more on the offical documentation. A simple working example could be the one you can see at fastify-multer:
const server = fastify()
// register fastify content parser
server.register(multer.contentParser)
server.route({
method: 'POST',
url: '/profile',
preHandler: upload.single('avatar'),
handler: function(request, reply) {
// request.file is the `avatar` file
// request.body will hold the text fields, if there were any
reply.code(200).send('SUCCESS')
}
})
If you need more help just provide me a repro repo on github and I'll try to figure out what is the best solution for your case.
Let me know! :)
I want to upload a .txt file to telegram with my javascript bot.
I've seen a few examples in php and python but didn't understand, so I just need a js example to find out.
Should I upload a file first and then sendDocmuent or should input in sendDocmuent?
I've tried sendDocument with document: 'file.txt' but didn't work.
Also read about form-data but got nothing!
call("sendDocument",{
chat_id: owner,
document: 'file.txt' // or /file.txt or full address (C:...)
});
I'm not using any library, here is my call function:
const botUrl = "https://api.telegram.org/bot" + token + "/";
const request = require('request');
function call(method, params, onResponse)
{
var requestData = params;
var data = {
url: botUrl+method,
json: true,
body: requestData
};
request.post(data, function(error, httpResponse, body){
if (onResponse) {
if(body)
{
onResponse(body.result);
}
}
});
}
Telegram bot API
EDITED: This is the code that works for me.
It seems that what the Telegram API never requires a file name for the sendDocument method:
File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data
Instead of just sending out the string 'file.txt', you need to actually send the contents of the file, as a multipart/form-data, as you had guessed. Building on this answer, you just need to modify the form field of the request object:
const request = require('request')
const fs = require('fs')
const token = '752511654:AAGnu88dyi7YsmpZfcaA6XvR26Fy7f2moGo'
const url = 'https://api.telegram.org/bot'+token+'/sendDocument'
const chat_id = "741718736"
let r = request(url, (err, res, body) => {
if(err) console.log(err)
console.log(body)
})
let f = r.form()
f.append('chat_id', chat_id)
f.append('document', fs.createReadStream('file.txt'))
I'm developing a chatbot using Microsoft Bot Framework with Node Js.
My purpose is to send the user a csv file while he asks me something.
I've implemented the following function but while I download the file 'prova.csv' the format is not recognized.
Inspecting well the format in output is of the type: "data"
Anyone can help me what's wrong? Thanks
function (session, results, next) {
if (results.response.entity === 'Si') {
const contentType = 'text/csv';
const response = session.dialogData.far_ric_formato.response.rows;
const csv = response.map(ric => `${ric.num};${ric.pin}`).join('\n');
session.send({
text: 'Ecco il CSV pronto per il download (MOCK)',
attachments: [
{
contentType: contentType,
contentUrl: `data:${contentType};base64,${Buffer.from(csv).toString('base64')}`,
name: 'prova.csv'
}
]
});
Base64 string of a .csv file can't be directly rendered on client side, as a workaround you can for example code like this:
var restify = require('restify');
var fs = require('fs');
bot.dialog('download', (session, result)=>{
fs.readFile('./files/test.csv', function(err, data){
var contentType = 'text/csv';
var base64 = Buffer.from(data).toString('base64');
var msg = new builder.Message(session)
.addAttachment({
contentUrl: 'http://localhost:3978/csv/'+base64, //replace with your server url + base64 string.
contentType: contentType,
name: 'MyTest.csv',
});
session.send(msg);
});
}).triggerAction({matches:/^download/i});
server.get('/csv/:base64code', (req, res, next)=>{
let base64code = req.params.base64code;
res.header('Content-disposition', 'inline; filename=test.csv');
res.header('Content-type', 'application/csv');
res.send(Buffer.from(base64code, 'base64'));
});
When user trigger the download dialog, it will send this file as attachment and when user click on this file, this .csv file will be downloaded in user's client side.
I have file from client that i have to read on server side and send back to client for download , How can i acheive that task using nodejs. I tried with fs but i am getting some error.
console.log(data) is coming as empty object
server.js
var multiparty = require('multiparty');
var data = new multiparty.Form();
export function create(req, res) {
data.parse(req, function(err, fields, files) {
console.log(files);
var fileContent = fs.readFileSync(files.file[0].path,'utf8');
res.json(fileContent );
});
}
router.js
var express = require('express');
var controller = require('./fileUpload.controller');
var router = express.Router();
router.post('/fileUpload',controller.create);
module.exports = router;
fileData
{ file:
[ { fieldName: 'file',
originalFilename: 'sco_poc.bpmn',
path: 'C:\\Users\\9u\\AppData\\Local\\Temp\\f4DG8L7nCpNyNvVPYqGPkd44.bpmn',
headers: [Object],
size: 11078 } ] }
I am assuming you are trying download a local file the path from your JSON object 'fileData'. My example below is written in NodeJS
First, you will need to stringify your JSONobject
var jsonString = JSON.stringify({ file:
[ { fieldName: 'file',
originalFilename: 'sco_poc.bpmn',
path: 'C:\\Users\\9u\\AppData\\Local\\Temp\\f4DG8L7nCpNyNvVPYqGPkd44.bpmn',
headers: [Object],
size: 11078 } ] });
//console.log(jsonString)//print jsonString contents
Second, parse it into a JavaScript object
var jsonObj = JSON.parse(jsonString);
//console.log(jsonObj); //print jsonObj contents
Third, get path from jsonObj
var path = jsonObj.file[0].path;
Finally, read the (local) file
fs.readFile(path,function(err,data){
var fileData="";
fileData+=data;
res.writeHead(200, {
'Location': '<if needed>',
'Content-Type':'<expected content-type>'
});
res.end(fileData); //ends response, and sends to client
});
If you look at the very first example on the multiparty NPM page here: https://www.npmjs.com/package/multiparty, you will see that you need to run this for each new request, not just once that you reuse over and over:
var form = new multiparty.Form();
So, for starter move that into your request handler. Then, if you're unsure how to use the results, I'd suggest you add this:
console.log(fields, files);
And, this should show you what data you actually have.
FYI, you can see errors in the parsing with this:
form.on('error', function(err) {
console.log('Error parsing form: ' + err.stack);
});
Also, note this statement from the documentation:
If cb is provided, autoFields and autoFiles are set to true and all
fields and files are collected and passed to the callback, removing
the need to listen to any events on form. This is for convenience when
you want to read everything, but be sure to write cleanup code, as
this will write all uploaded files to the disk, even ones you may not
be interested in.
You will need to cleanup files on disk after each request or they will accumulate.