Bad Gateway 502 on Openshift NodeJS app when uploading a file - angularjs

i've got an Application based on NodeJS and AngularJS and pushed it to openshift. But everytime i try to upload something, i get the following error:
POST http://www.domain.de/api/upload/file 502 (Bad Gateway)
Angular sends the data like this:
$scope.newFile = function() {
$scope.id = $scope.group._id;
var fd = new FormData();
var file = $scope.files[0];
fd.append('file', file);
if (file.type!="application/pdf"){
mvNotifier.error("Nur PDF Dateien sind akzeptiert.");
return;
}
$http.post('/api/upload/file', fd, {
transformRequest: angular.identity,
headers:{'Content-Type': undefined}
})
.success(function(d) {
var data = {
name: file.name,
description: $scope.descriptionfile
}
mvNotifier.notify("Bis hier hin klappt alles");
console.log("sucess on uploading ");
mvFactory.POST(data, mvGroup, {_place:"file", _id:$scope.id}).then(function(data) {
$scope.newfile=false;
$scope.group.files.push({name:file.name, description:$scope.descriptionfile});
mvNotifier.notify("Datei hochgeladen");
}, function(reason) {
mvNotifier.error("reason");
})
})
.error(function(data,status,header) {
mvNotifier.error("Upload hat nicht funktioniert.")
console.log("data", data);
console.log("status", status);
console.log("header", header);
})
And the Server routes to a file using busboy to save it:
uploadFile: function(req,res) {
console.log("req",req.files);
if (process.env.OPENSHIFT_DATA_DIR!= undefined) {
var cPath = process.env.OPENSHIFT_DATA_DIR;
} else {
var cPath = path.resolve('..', 'data');
}
var busboy = new Busboy({ headers: req.headers });
req.pipe(busboy);
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
var wPath = cPath + '/uploads/documents';
file.pipe(fs.createWriteStream(wPath + '/' + filename));
file.on('end', function() {
console.log('File [' + fieldname + '] Finished');
});
});
busboy.on('finish', function() {
console.log('Done parsing form!');
});
res.status(200).end();
}
On Localhost everything is working just fine and the data is saved to the server. but i get the response of bad gateway and this header:
<title>502 Bad Gateway</title>
</head><body>
<h1>Bad Gateway</h1>
<p>The proxy server received an invalid response from an upstream server.<br />
Can someone help me please?

I've resolved the issue. I post it so that someone who has the problem can solve it to.
The Web load balancer at openshift is HAproxy and has issues with the upload because the response of the server wasn't identical with the request because of the content type. I switched from $http from angular to an XHR. That solved the issue and works fine. The content-type i didn't set at all. now it works fine.

Related

Corrupt zip file downloaded in angular

Angular client code:
$http.post('/zip', {
id: _id
})
.success(function (data, status, headers, config) {
var blob = new Blob([data], {type: "application/zip"});
var contentDisp = headers('content-disposition');
if (contentDisp && /^attachment/i.test(contentDisp)) {
var fileName = contentDisp.toLowerCase()
.split('filename=')[1]
.split(';')[0]
.replace(/"/g, '');
//The below command works but generates a corrupt zip file.
FileSaver.saveAs(blob, fileName);
}
})
.error(function () {
console.log("Could not download");
});
NodeJS Server Code:
app.route('/zip/')
.post(function(req, res) {
var output = fs.createWriteStream(join(outdir, outzipfile));
//Using s3zip to archive.
s3Zip
.archive({ s3: s3Client, bucket: bucket}, folder, s3_files)
.pipe(output);
output.on('close', function() {
//This sends back a zip file.
res.download(outPutDirectory + outputBcemFile);
});
output.on('error', function(err) {
console.log(err);
return res.status(500).json({error: "Internal Server Error"});
});
});
Although FileSaver.saveAs works and downloads the zip file, it seems to be corrupted. Is the type "application/zip" correct? I have also tried "octet/stream" and it downloads a corrupt zip file too. Any help would be highly invaluable! Thanks.
This is a bug mentioned in Git in below link :
https://github.com/eligrey/FileSaver.js/issues/156
To solve you need to add : responseType: 'arraybuffer' to your $http Request headers and it will work.

Angularjs Access-Control-Allow-Origin

I have Angularjs app connects to a server using API, and i'm using token authentication, when i use Postman to get the token, it works perfect, but when i'm use Angulajs with the same header and parameters i got error:400.
When i checked both requests using Fiddler, i found that the request from Angularjs is missing Access-Control-Allow-Origin: * header.
How to fix this?
Here is the service used to get the token:
AuthenticationApi.Login = function (loginData) {
//POST's Object
var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
//the data will be sent the data as string not JSON object.
$http.post('http://localhost:53194/Token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
.then(function (response) {
console.log(response);
localStorageService.set('authorizationData',
{
token: response.access_token,
userName: loginData.userName
});
Authentication.isAuth = true;
Authentication.userName = loginData.userName;
console.log(Authentication);
deferred.resolve(response);
},
function (err, status) {
logout();
deferred.reject(err);
});
return deferred.promise;
};
for the API server, i'v done CORS:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
i found the problem and i fixed it.
in the API server, i have this code:
var cors = new EnableCorsAttribute("*", "*", "*");
cors.PreflightMaxAge = 60;
config.EnableCors(cors);
The problem is in the PreflightMaxAge, i just commented it...It worked!!!
if the problem not solved, try to use IE or FireFox, don't use Chrome because it is not CORS enabled

Angularjs - downloading a file in a specific location

here is the situation.
I have an angular app that need to be used via a machine on wich you can put an USB key.
Several exports are possible from the corresponding backend and thoses exports (pdf, csv or rtf) need to be downloaded directly on the key, without asking the user.
Furthermore I need to be able to detect if the key is not present and show an error.
I don't think that it is doable using only angular with chromium.
I was thinking of making a local nodejs server on each machine that could access the filesystem for that. It works when using postman with form-data, but I don't know how I can pass a file donwloaded in angular to the nodejs server as a formdata, I keep getting incorrect pdf files.
TLDR :
I need to be able to have a chain like this :
get file from backend in angular
post a request to local (nodejs) server with the downloaded file
receive the file in nodejs to save it on disk
I am open to other ideas if this one doesn't work, as long as I can download this file I am happy.
current nodejs code, that works when i post the file using postman :
router.post('/save', function(req, res, next) {
console.log('savexvbxc');
var fstream;
//test if USB key is available
fs.stat(basePath, function(err, stats) {
if (err) {
console.log('error, key not present');
res.send(412, 'FAILURE');
}
var filename = basePath + 'toti.pdf';
console.log('filename is ' + filename);
if (req.busboy) {
console.log('busboy loaded');
req.busboy.on('file', function(fieldName, fileStream, fileName, encoding, mimeType) {
console.log('Saving: ' + filename + ' ' + fileName);
fstream = fs.createWriteStream(filename);
fileStream.pipe(fstream);
fstream.on('close', function() {
console.log('successfully saved ' + filename);
res.status(200).send('SUCCESS');
});
fstream.on('error', function(error) {
console.log('failed saved ' + filename);
console.log(error);
res.send(500, 'FAILURE');
});
});
req.busboy.on('error', function(error) {
console.log('failed saved ' + filename);
console.log(error);
res.send(500, 'FAILURE');
});
return req.pipe(req.busboy);
} else {
console.log('error, busboy not loaded');
res.send(500, 'FAILURE');
}
});
});
current angular code that do not work:
var dlReq = {
method: 'GET',
url: '/fep/documents/TVFI_FEP_0015_SFS_Specifications_Fonctionnelles_Detaillees_V00.9.pdf',
headers: {
'Content-Type': 'application/pdf',
'Accept': 'http://localhost:4000/fep/documents/TVFI_FEP_0015_SFS_Specifications_Fonctionnelles_Detaillees_V00.9.pdf'
},
responseType: 'arraybuffer'
};
$http(dlReq).then(function(data, status, headers, config) {
console.log(resp);
var file = new Blob([(resp)], {type: 'application/pdf'});
var formdata = new FormData();
formdata.append('file', file);
var request = {
method: 'POST',
url: 'http://localhost:4080/save',
data: formdata,
headers: {
'Content-Type': undefined,
'Accept': '*/*'
}
};
// SEND THE FILES.
$http(request)
.success(function(d) {
console.log('ok', d);
})
.error(function() {
console.log('fail');
});
});
Thank you

nodejs write simple image blob - Upload.dataUrltoBlob

Simple question. How do I save a image blob in Nodejs from angular.
AngularSide:
$scope.upload = function (dataUrl, picFile) {
Upload.upload({
url: 'http://test.dev:3000/register/user/uploads',
data: {
file: Upload.dataUrltoBlob(dataUrl, picFile.name)
},
}).then(function (response) {
$timeout(function () {
$scope.result = response.data;
});
}, function (response) {
if (response.status > 0) $scope.errorMsg = response.status
+ ': ' + response.data;
}, function (evt) {
$scope.progress = parseInt(100.0 * evt.loaded / evt.total);
});
}
nodejs side: Do I need middleware here? if so which one should I use?
router.post('/user/uploads', multipartMiddleware, function(req, resp) {
var newPath = "/Users/testUser/test_hold_files/" + req.files.file.originalFilename;
fs.writeFile(newPath, req.files.file, function(err) {
if (err) {
console.log("Data Error ");
return console.error(err);
}
});
res.status(200).jsonp({status: "status: success "});
});
right now this just writes out the file with correct name but its empty.
You used to be able to access the uploaded file through req.files.imageName and then you would fs.readFile from tmp and write it permanently, which is no longer the case in express 4.0
In Express 4, req.files is no longer available on the req object by default. To access uploaded files on the req.files object, use multipart-handling middleware like busboy, multer, formidable, multiparty, connect-multiparty, or pez.
Soooooooo, you can feel free to use which ever one of those middlewares names above and then follow their API for dealing with uploaded files like images. Hope this helps, enjoy.
Ok,
After a long time of messing with this stuff. I found an answer. It does load the file in my folder.
I feel this is only partial since it does not resize the actual file smaller. It is what is selected with https://github.com/danialfarid/ng-file-upload. I used the
Upload.upload({
url: 'http://test.dev:3000/register/user/uploads',
data: {
file: Upload.dataUrltoBlob(dataUrl, picFile.name)
},
This did zoom into the file on selected image. It did not make the actual file size smaller. I am still looking into this issue.
var formidable = require('formidable'),
util = require('util'),
fs_extra = require('fs-extra');
This is my post to accept images.
router.post('/user/uploads', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
form.on('end', function(fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Location where we want to copy the uploaded file */
var new_location = "/Users/testUser/test_hold_files/";
fs_extra.copy(temp_path, new_location + file_name, function(err) {
if (err) {
console.error(err);
} else {
console.log("success!")
}
});
});
});
I have also noticed that I can view the file in chrome but not load it into gimp. Gimp gives me a file error.
Small steps I guess.
Maybe Datsik can give us some insight on what is going on here.
https://stackoverflow.com/users/2128168/datsik
Phil

posting scope variable through $http.post in angularjs

$http.post('/#/college', $scope.userb)
.success(function(data, status) {
console.log("Sent ok");
})
.error(function(data, status) {
console.log("Error");
})
[1]: http://i.stack.imgur.com/NlHyy.jpg
Is this the correct format/way to post my form data using http.post.?
The above code always returns "error" in the console.
please guide me to use http.post to post my form datathrough my controller.
var nodemailer = require("nodemailer");
var bodyparser = require("body-parser");
var app = express();
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "abc#gmail.com",
pass: "abc202"
}
});
var rand, mailOptions, host, link;
app.get('/#/college',function(req,res){
rand=Math.floor((Math.random() * 100) + 54);
host=req.get('host');
link="http://"+req.get('host')+"/verify?id="+rand;
mailOptions={
to : req.userb.counselloremail,
subject : "Please confirm your Email account",
html : "Hello,<br> Please Click on the link to verify your email.<br>Click here to verify"
}
console.log(mailOptions);
smtpTransport.sendMail(mailOptions, function(error, response){
if(error){
console.log(error);
res.end("error");
}else{
console.log("Message sent: " + response.message);
res.end("sent");
}
});
app.use(morgan('dev'));
app.use(gzippo.staticGzip("" + __dirname + "/dist"));
app.listen(process.env.PORT || 5000);
I am trying to access the email address from the scope variable and post it so that i may send a confirmation mail that he is successfully registered now. Also I am sending the code of my web.js file that receives the posted data and sends the mail.
That URL you are posting to is not going to be valid.
If you are posting to another route in your app, the URL would just be #/college.
I'm also a little worried that you don't have anything setup to receive a post request, like on a server or anything. Could you give some more detail about what you are trying to do and your setup?
var dataObject = {
userid : LoginUserID
};
var responsePromise = $http.post(ApiAccessUrl+"/store/userstoreslist/", dataObject, {});
responsePromise.success(function(dataFromServer, status, headers, config)
{
var outputDate=angular.fromJson(dataFromServer);
});
responsePromise.error(function(data, status, headers, config) {
console.log("Error in fetching user store call!");
});
This is the correct way of sending data using http.post

Resources