0

I need to upload a file which contains some headers informations and lots of points (x, y, z) to server (for now localhost) using nodeJS.

For now I'm able to properly upload a png file using this code for the iOS side :

- (IBAction)uploadFileButton:(id)sender {
    NSLog(@"Going to upload file");
    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:"http://localhost:3000/"]];

    request.HTTPMethod = @"POST";
    [request addValue:@"image/png" forHTTPHeaderField:@"Content-Type"];

    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
    //UIImagePNGRepresentation turns an instance of UIImage into PNG file data.
    NSData* bytes = UIImagePNGRepresentation(self.imageView.image);//a random image displayed on my iOS view for testing purpose

    NSURLSessionUploadTask* task = [session uploadTaskWithRequest:request fromData:bytes completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { //5
        if (error == nil && [(NSHTTPURLResponse*)response statusCode] < 300) {
            NSDictionary* responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

        }
    }];
    [task resume];
}

And using this code (just the interesting part) for the server side :

app.post('/',function(req,res){
   //This looks up the value of the Content-Type header which is set by the mobile app.
    var ctype = req.get("content-type");
    //This tries to guess the file extension based upon the content type. For instance, an image/png should have a png extension.
    var ext = ctype.substr(ctype.indexOf('/')+1); 
    if (ext) {ext = '.' + ext; } else {ext = '';}

    //Create a filename by appending the appropriate extension to the new id.    
    var filename = "test" + ext;
    console.log("filename : " + filename);
    //The designated path to the file is in the server’s root directory, under the uploads sub-folder. __dirname is the Node.js value of the executing script’s directory.
    filePath = __dirname + '/uploads/' + filename; 

     console.log("filepath : " + filePath);
    var writable = fs.createWriteStream(filePath); 

    req.pipe(writable); 
    req.on('end', function (){ 
      res.send(201, "ok");
    });        

    writable.on('error', function(err) { 
      res.send(500,err);
      console.log("Error uploading file.");
    });

});

So far, after some struggling, I'm able to upload a png file to uploads directory.

Now I would like to go further by upload a specific file with a specific extension.

I tried to change

[request addValue:@"image/png" forHTTPHeaderField:@"Content-Type"];

to

 [request addValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"];

but I'm stuck about converting to NSData type.

So do you have an idea how I can upload a file (not an image) to my server ? I tried to search on the internet but I did not find any related answers.

However, I was wondering, if maybe I need to convert my file to json file and then upload it to the server ? (I think it's easier to upload json files.)

Could you please help me ?

Thank you a lot in advance for your help.

EDIT : Tried with AFNetworking and still not working

I tried with the library AFNetworking with the following code but it's not working. I don't have any errors.

   NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

   manager.responseSerializer = [AFHTTPResponseSerializer serializer];

  manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    NSURL *URL = [NSURL URLWithString:"http://localhost:3000/"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES ) objectAtIndex:0];
    NSString *data = @"Model.pcd";
    NSString *data_path = [documentsDirectoryPath stringByAppendingPathComponent:data];
    NSLog(@"path: %@ ", data_path);

    NSURL *filePath = [NSURL fileURLWithPath:data_path];
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            NSLog(@"[INFO] Error: %@", error);
        } else {
            NSLog(@"[INFO]Upload successfully : %@ %@", response, responseObject);
        }
    }];
    [uploadTask resume];

First I had the following error :

NSLocalizedDescription=Request failed: unacceptable content-type: text/html

But by adding manager.responseSerializer = [AFHTTPResponseSerializer serializer]; I don't have any errors.

But the upload did not work...

My output is the following :

NSHTTPURLResponse: 0x6180002310a0> { URL: http://localhost:3000/ } { status code: 200, headers {
    "Accept-Ranges" = bytes;
    "Cache-Control" = "public, max-age=0";
    Connection = "keep-alive";
    "Content-Length" = 233;
    "Content-Type" = "text/html; charset=UTF-8";
    Date = "Thu, 13 Oct 2016 12:03:58 GMT";
    Etag = "\"233-1476189758000\"";
    "Last-Modified" = "Tue, 11 Oct 2016 12:42:38 GMT";
    "X-Powered-By" = Express;
} } <3c666f72 6d206964 20202020 20202020 3d202022 75706c6f 6164466f 726d220a 20202020 20656e63 74797065 2020203d 2020226d 756c7469 70617274 2f666f72 6d2d6461 7461220a 20202020 20616374 696f6e20 2020203d 2020222f 6170692f 70686f74 6f220a20 20202020 6d657468 6f642020 20203d20 2022706f 7374220a 3e0a3c69 6e707574 20747970 653d2266 696c6522 206e616d 653d2275 73657250 686f746f 22202f3e 0a3c696e 70757420 74797065 3d227375 626d6974 22207661 6c75653d 2255706c 6f616420 496d6167 6522206e 616d653d 22737562 6d697422 3e0a3c2f 666f726d 3e>
vaibhav
  • 4,038
  • 1
  • 21
  • 51
lilouch
  • 1,054
  • 4
  • 23
  • 43
  • you must change the uploading code have a look my ans containing some working links. – vaibhav Oct 13 '16 at 12:02
  • Not a solution, but you could do in the block to help you debug: `if ([responseObject isKindOfClass:[NSData class]]){NSLog(@"responseObject: %@", [[NSString alloc] initWithData: responseObject encoding:NSUTF8StringEncoding];}` instead of printing the NSData which doesn't help ;) – Larme Oct 14 '16 at 15:08

1 Answers1

0

Okey I struggled a lot but finally I was able to upload a file using two methods : Multer and AFNetworking.

Actually I had an error on my form that's why nothing happened. Here the code iOS side :

//Content type
NSDictionary *params = @{@"enctype": @"multipart/form-data"};
NSLog(@"Upload file...");

//Path to the local file (TODO : need to change once the app will be on the ipad)
NSString *path_data = @"file.xyz";
//Check if the file exist
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:cloud_pcd_path];
if (!fileExists){
    NSLog(@"ERROR - FILE NOT EXIST ");
    return;

}
//Transform the data to NSData for sending to the server
NSData *cloudData = [NSData dataWithContentsOfFile:path_data];


//Create a HTTP request type POST for sending the data
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:kBaseURL
                                                                            parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
    /// Add attributes to the forms for using then in NodeJS
    [formData appendPartWithFileData:cloudData
                                name:@"data"
                            fileName:@"file.xyz"
                            mimeType:@"text/plain"];

} error:nil];


[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:20];

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];


manager.responseSerializer = [AFHTTPResponseSerializer serializer];
//Upload it
//Upload tasks are used for making HTTP requests that require a request body
NSURLSessionUploadTask *uploadTask;

// Create a progress object and pass it in
__block NSProgress *prog;
uploadTask = [manager uploadTaskWithStreamedRequest:request
                                           progress:^(NSProgress *_Nonnull progress){
                                               [progress addObserver:self
                                                          forKeyPath:@"fractionCompleted"
                                                             options:NSKeyValueObservingOptionNew
                                                             context:NULL];

                                               prog = progress;
                                              // [self unregisterAsObserverForObject:progress];
                                           }
                                  completionHandler:^(NSURLResponse * response, id responseObject, NSError * error)
{
    if (error) {
        NSLog(@"[INFO] ERROR: %@", error);
    } else {
        NSLog(@"[INFO] Upload completed");
    }

}];

And the code in NodeJS using Multer :

//Parameters for uploading file
var storage = multer.diskStorage({
    destination: function (request, file, callback) {
        callback(null, './uploads/');
    },
    filename: function (request, file, callback) {
        console.log(file);
        callback(null, file.originalname)
    }
});

var upload = multer({ storage: storage }).single('data');

router.get('/', function (req, res, next) {
    res.send('<html><body><h1>Upload</h1></body></html>');

});


router.post('/', function (req, res) {
  upload(req, res, function (err) {
    if (err) {
      // An error occurred when uploading
      console.log("ERROR during the upload");
      return

    }else 
    {


        // Everything went fine
    console.log("File uploaded : ",req.file.originalname);
    console.log("Saved to : ",req.file.destination);
  res.status(204).end()

 }
  })

});

I can now continue my project.

Thank

lilouch
  • 1,054
  • 4
  • 23
  • 43