简体   繁体   中英

Send a file from mobile to Node js server

I'm doing an application with react-native. Now I'm trying to send an image from the mobile to the server (Node Js). For this I'm using react-native-image-picker. And the problem is that when I send the image it save a file but it's empty not contain the photo. I think that the problem probably is that the server can't access to the path of the image because is in a different device. But I don't know how I can do it.

React-Native:

openImagePicker(){
      const options = {
        title: 'Select Avatar',
         storageOptions: {
          skipBackup: true,
          path: 'images'
      }
      }

      ImagePicker.showImagePicker(options, (imagen) =>{
          if (imagen.didCancel) {
        console.log('User cancelled image picker');
      }
      else if (imagen.error) {
        console.log('ImagePicker Error: ', imagen.error);
      }
      else if (imagen.customButton) {
        console.log('User tapped custom button: ', imagen.customButton);
      }
      else {
    let formdata = new FormData();
    formdata.append("file[name]", imagen.fileName);
    formdata.append("file[path]", imagen.path);
    formdata.append("file[type]", imagen.type);
            fetch('http://X/user/photo/58e137dd5d45090d0b000006', {
      method: 'PUT',
      headers: {
         'Content-Type': 'multipart/form-data'
      },
      body: formdata
    })
        .then(response => {
          console.log("ok");       
      })
       .catch(function(err) {
          console.log(err);
      })  
    }})}

Node Js:

    addPhotoUser = function (req, res) {
User.findById(req.params.id, function(err, user) {
fs.readFile(req.body.file.path, function (err, data) {      
  var pwd = 'home/ubuntu/.../';
  var newPath = pwd + req.body.file.name;
  fs.writeFile(newPath, data, function (err) {
    imageUrl: URL + req.body.file.name;
        user.save(function(err) {
            if(!err) {
                console.log('Updated');
            } else {
                console.log('ERROR: ' + err);
            }
            res.send(user);
        });

  });
});
});
};

Make an object then send that object to the server. The object will consist of name,path and type, like this:

var imageData = {name: 'image1', path: uri, type: 'image/jpeg'} 

Above is a one way to send the image data. The other way is to convert it into BLOB so that server side programmer doesn't have to do this task on their end. You can make BLOB by use of react-native-fetch-blob .

One more way is to directly upload the images to the amazon server(s3) and send the link to the backend..

Function that returns base64 string:

var RNFetchBlob = require('react-native-fetch-blob').default;

getImageAttachment: function(uri_attachment, mimetype_attachment) {

  return new Promise((RESOLVE, REJECT) => {

    // Fetch attachment
    RNFetchBlob.fetch('GET', config.apiRoot+'/app/'+uri_attachment)
      .then((response) => {

        let base64Str = response.data;
        var imageBase64 = 'data:'+mimetype_attachment+';base64,'+base64Str;
        // Return base64 image
        RESOLVE(imageBase64)
     })

   }).catch((error) => {
   // error handling
   console.log("Error: ", error)
 });
},

Cheers :)

Yes, the problem is that the filepath is on the local device and not the server. You want to send the actual data returned to you by react-native-image-picker not the uri. It looks like that library encodes the data with base64 so you're going to want send that to your server, not the uri returned from the library because it won't be accessible on a remote server.

What this means is that you won't be reading any files on your server but instead just decoding a base64 string in the response body and writing that to your filesystem.

For the client side:

let formdata = new FormData();
formdata.append("file[name]", imagen.fileName);
formdata.append("file[data]", imagen.data); // this is base64 encoded!
formdata.append("file[type]", imagen.type);
        fetch('http://X/user/photo/58e137dd5d45090d0b000006', {
  method: 'PUT',
  headers: {
     'Content-Type': 'multipart/form-data'
  },
  body: formdata
})

On the server side atob to decode from base64 before writing to the filesystem:

let decoded = atob(req.body.data) 
// now this is binary and can written to the filesystem

From there:

fs.writeFile(newPath, decoded, function (err) {
    imageUrl: newPath;
        user.save(function(err) {
            if(!err) {
                console.log('Updated');
            } else {
                console.log('ERROR: ' + err);
            }
            res.send(user);
        });

  });

Note, you don't need the filesystem write that's in your code because you're decoding the image that was sent as a b64 string in your request.

There also seems to be some oddities with how you're using that user object. You seem to be only passing a function that handles errors and not any actual data. I don't know what ORM you're using so it's hard to say how it should work. Maybe something like this?

user.save({imageUrl:uriReturnedByFsWrite}, (err, data)=>{...})

Good luck :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM