Pankaj Pankaj - 4 months ago 37
Node.js Question

objective c multipart form file upload with user credentials

I have the following code in objective C that works just fine for uploading a file via POST to node.js /formidable.

I would however like to include user credentials and additional details about the file in this POST request. I have looked all over and could not find an example that would allow me to achieve this.

Please advice what do I need to achieve the objective above.

Here is my code in Objective C:

-(void) uploadToServer:(NSData*) mediaData
asType:(int) mediaType
asFile:(NSString*) saveFileAs{

NSDictionary *params = @{@"subFolder" : G_deviceName,
@"filename" : saveFileAs
};

NSString *boundary = [self generateBoundaryString];


// configure the request

NSString * urlForUploading = [NSString stringWithFormat:@"%@/upload",G_appServerURL ];

NSURL *uploadToURL = [NSURL URLWithString:urlForUploading];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:uploadToURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:@"POST"];

// set content type

NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];

// create body

NSData *httpBody = [self createBodyWithBoundary:boundary parameters:params mediaData:mediaData fieldName:@"fieldName"];

self.session = [NSURLSession sharedSession]; // use sharedSession or create your own

NSURLSessionTask *task = [self.session uploadTaskWithRequest:request fromData:httpBody completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"error = %@", error);
[[NSNotificationCenter defaultCenter] postNotificationName:@"activeUpload" object:nil userInfo:nil];
return;
}
else{
NSLog(@"uploadToServer successful." );

[[NSNotificationCenter defaultCenter] postNotificationName:@"activeUpload" object:nil userInfo:nil];
}

NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"result = %@", result);
}];
[task resume];

}

- (NSData *)createBodyWithBoundary:(NSString *)boundary
parameters:(NSDictionary *)parameters
mediaData:(NSData*)mediaData
fieldName:(NSString *)fieldName
{
NSMutableData *httpBody = [NSMutableData data];

// add params (all params are strings)

[parameters enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) {
[httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"%@\r\n", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]];
}];

// add image data

NSString *formName = [parameters objectForKey:@"subFolder"];
NSString *filename = [parameters objectForKey:@"filename"];
NSString *mimetype = @"image/jpeg"; //[self mimeTypeForPath:path];

[httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", formName, filename] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:mediaData];
[httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

[httpBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

return httpBody;
}

- (NSString *)generateBoundaryString
{
return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];

}


Here is the code in node.js Server that receives this POST request and saves the file:

app.post('/upload', function(req, res){

var subFolder;

// create an incoming form object
var form = new formidable.IncomingForm();

form.multiples = false;

form.uploadDir = '/home/uploads'

form.on('fileBegin', function(name, file) {

console.log('entered fileBegin ... ');
form.uploadDir = form.uploadDir + name;

});

// every time a file has been uploaded successfully, rename it to it's orignal name
form.on('file', function(field, file) {
fs.rename(file.path, path.join(form.uploadDir, file.name));

});


form.parse(req, function(err, fields, files) {
if (err)
console.log("In form.parse, error occured : " + util.inspect(err));

console.log("parsing form now...");

});

// log any errors that occur
form.on('error', function(err) {
console.log('An error has occured: \n' + err);
});

// once all the files have been uploaded, send a response to the client
form.on('end', function() {
console.log('File uploaded to location : ' + form.uploadDir);
res.end('success');
});


});

Answer

I guess form.parse provides those extra params

 form.parse(req, function(err, fields, files) {
   console.log("parsing form now..."+ JSON.stringify(fields));
 });

In case you still want earlier then check this

 form.on('field', function(name, value) { }); 

and in case that also comes late then try re-ordering the sequence from HTML form

Comments