3

I'm trying to use the camera plugin and file transfer on my project. They work fine on android but when I tested on ios simulator, I'm getting an empty request body on the server when I try to upload a photo using the cordova file transfer plugin.

In the code below, the photo_url is the response that I get from the camera plugin. This contains the full path of the photo that I selected from the gallery. Here's the value that I got when I used console.log:

file:///Users/user/Library/Developer/CoreSimulator/Devices/87045654-FB0C-40E8-97A8-5634FC2D05E7/data/Containers/Data/Application/E0810976-FF0F-43E2-BC15-3EFDD93D61C4/tmp/cdv_photo_010.jpg

Here's the code:

 var options = new FileUploadOptions();
      options.fileKey = 'file';
      options.fileName = photo_url.substr(photo_url.lastIndexOf('/') + 1).split('?')[0];
      options.mimeType = 'image/jpeg';
      options.params = params;

      var ft = new FileTransfer();
      ft.upload(
        photo_url, me.upload_url + path + '/photo/upload', 
        function(result){
          console.log('success');
          console.log(result);
        },
        function(err){
          console.log('error');
          console.log(err);
        }, 
        options
      );

The value for options.fileName is: cdv_photo_010.jpg.

I tried looking for solutions and I found the following:

options.headers = {
 Connection: "close"
};

options.chunkedMode = false;

I applied it to my existing code but it still didn't work. The request body that I'm getting in the server is still an empty object.

I'm using an express server and multer to handle file uploads.

Here's the code on the server:

var multer_options = { 
    dest: './public/uploads',
    fileSize: '',
    fields: 10,
    files: 1,
    rename: function(fieldname, filename){
        return random.string(30) + '-' + Date.now();
    },
    changeDest: function(original_dest, req, res){

        console.log('org dest:');
        console.log(original_dest);

        console.log('request body: ');
        console.log(req.body);

        var j = JSON.parse(req.body);
        console.log('parsed body: ');
        console.log(j);

        var request_data = req.body.request_data;
        console.log('request data: ');
        console.log(request_data);
        var dest = original_dest + '/' + request_data.upload_path;

        console.log('upload path: ');
        console.log(request_data.upload_path);

        console.log('dest: ');
        console.log(dest);

        var stat = null;

        try{
            stat = fs.statSync(dest);
        }catch(err){
            fs.mkdirSync(dest);
        }

        if(stat && !stat.isDirectory()){
            throw new Error('Directory cannot be created because an inode of a different type exists at "' + dest + '"');
        }

        return dest;
    }
};

Multer already handles the file upload, so all I have to do is write the code for instructing multer to change the destination directory, which is what I have above. When uploading files in android, it works fine. I get values for the request body. But on ios its empty. So I think the problem is either with ios simulator or the file transfer plugin has issues when working with ios simulator.

Any ideas?

Wern Ancheta
  • 22,397
  • 38
  • 100
  • 139

1 Answers1

0

File Upload: Cordova File Transfer Plugin + ExpressJs Multer

The solution below lets me take a photo with the iPhone camera, and then uploads the photo to a NodeJS server.

@Kyokasuigetsu - almost gave up on FILE_URI with Cordova's File Transfer Plugin as well!


Notice that options.fileKey = 'myPhoto' and upload.single('myPhoto') should have the same value. It refers to the field name for the file upload form.

<!-- Upload a single file -->
<form>  
  <input type="file" name="myPhoto" />
</form>

Install needed plugins and modules (from console)

> cordova plugin add cordova-plugin-file-transfer;
> npm install express multer --save;

Cordova (native_app.js)

function uploadPhoto(fileUri) {
  // file:///var/mobile/Containers/Data/Application/
  // .../tmp/cdv_photo.jpg
  console.log("fileUri:", fileUri);

  var options, request;

  options = new FileUploadOptions();
  // The name 'fileKey' is confusing; it should be 'fieldname'
  options.fileKey = 'myPhoto';
  // fileName: 'cdv_photo.jpg';
  options.fileName =
    fileUri.substr(fileUri.lastIndexOf('/') + 1);

  request = new FileTransfer();
  request.upload(
    fileUri,
    encodeURI('http://localhost:8080/photos'),
    function success(response) {
      console.log("Success: Photo uploaded to server!");
    },
    function error(response) {
      console.log("Error: Photo not uploaded to server!");
    },
    options
  );
}

function capturePhoto(callback) {

  navigator.camera.getPicture(
    function success(fileUri) {
      callback(fileUri);
    },
    function error() {},
    { // camera options
      destinationType: Camera.DestinationType.FILE_URI,
      sourceType: Camera.PictureSourceType.CAMERA,
      encodingType: Camera.EncodingType.JPEG,
      mediaType: Camera.MediaType.PICTURE
    }
  );

}

function captureAndUploadPhoto() {
  capturePhoto(function (fileUrl) {
    uploadPhoto(fileUrl);
  });
}

document.addEventListener("deviceready", captureAndUploadPhoto, false);

NodeJs / ExpressJs (server_app.js)

var express, application, multer, upload;

express = require('express');
application = express();
multer  = require('multer');
upload = multer({dest: 'uploads/'}).single('myPhoto');

application.get('/photos', upload, function (request, response) {
  console.log(response.file);
  response.status(204).end();
});

application.listen(8080, function () {
  console.log('Example application listening on port 8080!');
});
Community
  • 1
  • 1
tim-montague
  • 16,217
  • 5
  • 62
  • 51