I've finally got the jsreportonline at least generating the file. Here's my code:
request.post({
url: 'https://xxxx.jsreportonline.net/api/report',
json: true,
headers: {
"Content-Type": "application/json",
"Authorization" : "Basic "+new Buffer(username:pwd).toString('base64')
},
body: {
"template" : {'shortid" : xxxxx},
"data" : xxxx,
}
}, function(err, res, body) {
**** HERE IS THE PROBLEM ****
});
I have no clue how to write the pdf output stored within variable 'body' to a file. I've tried:
var pbs = fs.createWriteStream('./report.pdf');
pbs.write(body);
pbs.end();
I've tried:
var pbs = fs.createWriteStream('./report.pdf', {defaultEncoding: 'binary'});
... but the PDF file never is displayed properly. I know the code works because I can set an option on the call:
"options" : {
"reports" : {"save" : true}
}
... and the report is saved to my jsreportonline account and renders fine.
Thanks for any help.
You shouldn't use the callback but rather directly pipe the stream returned from the request.post. See this in docs here. Example:
var request = require('request')
var fs = require('fs')
request.post({
url: 'https://xxx.jsreportonline.net/api/report',
json: true,
headers: {
'Content-Type': 'application/json',
'Authorization' : 'Basic '+new Buffer('xxx:yyy').toString('base64')
},
body: {
'template' : {'shortid" : xxxxx},
'data' : xxxx,
}
}).on('error', function (err) {
console.log(err)
}).pipe(fs.createWriteStream('report.pdf'))
You can use 'busboy' to write the uploaded file to a file in server directory.
Saving the file:-
var
express = require("express"), os = require('os'), path = require('path'), Busboy = require('busboy'), fs = require('fs'), app = express();
app.post('/savepdf', function(req, res) {
var busboy = new Busboy({
headers : req.headers
});
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log("OS tmp dir ========>" + os.tmpDir());
console.log("Base name ========>" + path.basename(filename));
var saveTo = path.join(os.tmpDir(), path.basename(filename));
file.pipe(fs.createWriteStream(saveTo));
});
busboy.on('finish', function() {
res.writeHead(200, {
'Connection' : 'close'
});
console.log("Upload finished !!!");
res.end("Success!");
});
return req.pipe(busboy);
});
app.listen(3000);
console.log('app started ');
HTML Page used to test the file:-
<html>
<head>
<title>Post Tool</title>
</head>
<body>
<h1>Save PDF </h1>
<h2>Upload Document</h2>
<form action="/savepdf" method="post" enctype="multipart/form-data">
<input type="text" name="uploadtext" id="uploadtext" value="Good" />
Choose a file : <input type="file" name="uploadfile" id="uploadfile" multiple/>
<input type="submit" value="Upload" />
</form>
</body>
</html>
Output:-
The file has been saved successfully in temp folder (i.e. windows path below).
C:\Users\userid\AppData\Local\Temp
The file name would be same as the uploaded file name.
Related
I am developing a website with angular.js and node.js, there is a need for upload function in this and I have succeeded in sending the object file from the front end i.e; angular using POST method but when the server receives the file the object file is saved as string file. How do I receive the object file as object file at the server end(node) or how do I convert the string file as object file again?
I have tried sending the file as data and image in the request header and body but it was not successful. The object file received is in the string format
controller:
var formdata = new FormData();
vm.getTheFiles = function ($files) {
alert($files[0]);
vm.uploadme= $files[0];
formdata.append('image', $files[0])
angular.forEach($files, function (value, key) {
formdata.append(key, value);
console.log('fileeeeeeeeeeeeeeee' + key + ' ' + value);
});
for (var pair of formdata.entries()) {
console.log(pair[1]);
}
};
vm.uploadFiles = function () {
console.log(vm.uploadme);
var request = {
method: 'POST',
url: '/api/users/upload/',
data: formdata,
headers: {
'Content-Type': undefined,
data: formdata
}
};
// SEND THE FILES.
$http(request)
.success(function (d) {
alert(d);
})
.error(function () {
});
}
HTML:
<input type="file" fileread="vm.uploadme" ng-files="vm.getTheFiles($files)" />
<input type="button" ng-click="vm.uploadFiles()" value="Upload" />
Node:
function upload(req, res) {
console.log('data',req.headers.data);
var formdata = req.headers.data;
var fs = require("fs");
var filePathFinal1 = '/images/profile/' + formdata + '.png';
fs.createWriteStream('app' + filePathFinal1);
res.sendStatus(200);
}
In the above node code I receive the display as string but I want the object file as it is.
I've spent hours trying to find the solution for something which should be quite simple: uploading a file to the server from the client. I am using React.js on the frontend, Express on the backend, and multer for the image uploads.
When I try to upload a file, nothing happens. An uploads/ directory is created, but no file goes there. req.file and req.files are undefined. req.body.file is empty. The form data exists before it is sent.
If I set the Content-Type header to "multipart/form-data" I get a boundary error from multer.
Input
<input
onChange={this.sendFile}
name="avatar"
placeholder="Choose avatar"
type="file"
/>
sendFile
sendFile = e => {
const data = new FormData();
const file = e.target.files[0];
data.append("file", file);
this.props.sendFile(data);
};
Redux action
export default file => async dispatch => {
const res = await axios.post("/api/upload/", { file });
};
Express
const multer = require("multer");
const upload = multer({ dest: "uploads/" });
router.post("/upload/", upload.single("avatar"), (req, res) => {
return res.sendStatus(200);
});
I tried to reproduce it and made it work with this method:
sendFile = e => {
const data = new FormData();
const file = e.target.files[0];
data.append("avatar", file); // <-- use "avatar" instead of "file" here
axios({
method: 'post',
url: 'http://localhost:9000/api/upload',
data: data,
config: { headers: { 'Content-Type': 'multipart/form-data' } }
});
};
Try to set the content-type header to multipart/form-data in the axios request and send the full FormData object as the second parameter.
Like this:
const config = {
headers: {
'content-type': 'multipart/form-data'
}
};
axios.post('/api/upload/', file, headers);`
I have the following route in hapijs server. And i am trying to create a new file using ajax.
{
method: 'POST',
path: '/create',
config : {
payload:{
maxBytes: 10*1024*1024,
output:'stream',
parse: true,
allow: 'multipart/form-data'
},
handler: function (request, reply) {
var data = request.payload;
if (data.file) { // undefined always
var name = data.file.hapi.filename;
var path = writePath + '/' + name;
var file = fs.createWriteStream(path);
file.on('error', reply);
data.file.pipe(file);
data.file.on('end', function (err) {
reply({
filename: data.file.hapi.filename,
headers: data.file.hapi.headers
});
});
} else reply(boom.badRequest('No file found. Please try again.'));
}
}
The above code always give data.file as undefined. Anything am i missing?
In hapi documentation http://hapijs.com/api#requests, when output is stream
'stream' - the incoming payload is made available via a
Stream.Readable interface. If the payload is 'multipart/form-data' and
parse is true, fields values are presented as text while files are
provided as streams. File streams from a 'multipart/form-data' upload
will also have a property hapi containing filename and headers
properties.
html code :
<form enctype="multipart/form-data" action="/create" method="post">
<input type="file" id="UniqueFileImporter"/>
<input type="submit"/>
</form>
of course there is no js code, as i simply need to submit the form after selecting a file from system
thanks to Matt Harrison for pointing out mistake, i was missing attribute name in file inputer.
html should be
<form enctype="multipart/form-data" action="/create" method="post">
<input type="file" name="file" id="UniqueFileImporter"/>
<input type="submit"/>
</form>
I am trying to upload a photo via a POST request with the request module
According to the readme I should just be able to do this
var r = request.post("http://posttestserver.com/post.php", requestCallback)
var form = r.form()
form.append("folder_id", "0");
form.append("filename", fs.createReadStream(path.join(__dirname, "image.png")));
function requestCallback(err, res, body) {
console.log(body);
}
The problem is, this doesn't work. I get a reply from the test server saying it dumped 0 post variables.
I have confirmed that the server is in working condition with this little html page
<html>
<body>
<form action="http://posttestserver.com/post.php?dir=example" method="post" enctype="multipart/form-data">
File: <input type="file" name="submitted">
<input type="hidden" name="someParam" value="someValue"/>
<input type="submit" value="send">
</form>
</body>
</html>
So the question is, what am I doing wrong with the request module? Is there a better way to send multipart/form-data with node?
After some more research, I decided to use the restler module. It makes the multipart upload really easy.
fs.stat("image.jpg", function(err, stats) {
restler.post("http://posttestserver.com/post.php", {
multipart: true,
data: {
"folder_id": "0",
"filename": restler.file("image.jpg", null, stats.size, null, "image/jpg")
}
}).on("complete", function(data) {
console.log(data);
});
});
So I just got done wrestling with this myself and here is what I learned:
It turns out that neither request or form-data are setting the content-length header for the generated body stream.
Here is the reported issue: https://github.com/mikeal/request/issues/316
The solution posted by #lildemon gets around this by:
Generating the FormData object
Getting it's length
Making the request and setting the form object and content-length header explicitly
Here is a modified version of your example:
var request = require('request');
var FormData = require('form-data');
var form = new FormData();
form.append("folder_id", "0");
form.append("filename", fs.createReadStream(path.join(__dirname, "image.png")));
form.getLength(function(err, length){
if (err) {
return requestCallback(err);
}
var r = request.post("http://posttestserver.com/post.php", requestCallback);
r._form = form;
r.setHeader('content-length', length);
});
function requestCallback(err, res, body) {
console.log(body);
}
I have working code that does exactly what your question states, with one exception. My file content is appended this way:
form.append('file', new Buffer(...),
{contentType: 'image/jpeg', filename: 'x.jpg'});
To discover the final options argument I had to drill down into the source of form-data. But this gives me a working configuration. (Maybe it was what you were missing, but of course that will depend on the server.)
I tried also request and form-data modules and was unable to upload a file.
You can use superagent which works:
http://visionmedia.github.io/superagent/#multipart-requests.
var request = require('superagent');
var agent1 = request.agent();
agent1.post('url/fileUpload')
.attach('file',__dirname + "/test.png")
.end(function(err, res) {
if (err) {
console.log(err)
}
});
Try request module. It works like any other normal post request
var jsonUpload = { };
var formData = {
'file': fs.createReadStream(fileName),
'jsonUpload': JSON.stringify(jsonUpload)
};
var uploadOptions = {
"url": "https://upload/url",
"method": "POST",
"headers": {
"Authorization": "Bearer " + accessToken
},
"formData": formData
}
var req = request(uploadOptions, function(err, resp, body) {
if (err) {
console.log('Error ', err);
} else {
console.log('upload successful', body)
}
});
I am posting to a formidable form from AngularJS, but the form does not parse. I do not use the express.bodyParser(), which I understand often is a problem.
serverside:
...
var form = new formidable.IncomingForm();
console.log(form); //this prints
//Get access to the other fields of the request.
form.parse(req, function (err, fields, files) {
console.log("parsing.."); //this does not print
console.log(fields);
console.log(files);`
...
client-side:
...
$http({
method: 'POST',
url: '/api/ad',
data: message, // your original form data,
transformRequest: formDataObject, // this sends your data to the formDataObject provider that we are defining below. `[see this](https://stackoverflow.com/questions/17629126/how-to-upload-a-file-using-angularjs-like-the-traditional-way)`
headers: {'Content-Type': undefined}
})
.success(function(data, status, headers, config){
deferred.resolve(data); `
...
When posting form Angular with the formData object, I have to set the content/type to undefined as mentioned in the comment here. Might that be a problem for formidable?
I have been using hours to try to figure this out with no luck. I would be very grateful for any answers!
I figured out this. I had to bind the files to the controller, as well as using the angular.identity function. Based on this great explanation I added the following to my angular code in order to bind files to the controller: `
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;`
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
and the following to post my form to the url I wanted:
myApp.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(data, uploadUrl){
var fd = new FormData();
angular.forEach(data, function(value, key) {
fd.append(key, value);
});
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(retObj){
console.log(retObj);
})
.error(function(retObj){
console.log(retObj);
});
}
}]);
In the submit-function in the controller I now add:
var formData = $scope.newForm;
var uploadUrl = '/api/add';
fileUpload.uploadFileToUrl(formData, uploadUrl);
and in my html, files-inputs gets the following tag in order to use the created file-model:
<input type="file" file-model="newForm.image1">
and my text inputs are just binded as before:
<input type="text" ng-model="newForm.title">
Hope this helps someone else :)