【问题标题】:How to upload files from ReactJS to Express endpoint如何将文件从 ReactJS 上传到 Express 端点
【发布时间】:2015-01-18 16:02:38
【问题描述】:

在我目前正在处理的应用程序中,有几个文件表单通过superagent 提交到 Express API 端点。比如图片数据是这样发布的:

handleSubmit: function(evt) {
    var imageData = new FormData();

    if ( this.state.image ) {
       imageData.append('image', this.state.image);
       AwsAPI.uploadImage(imageData, 'user', user.id).then(function(uploadedImage) {
         console.log('image uploaded:', uploadedImage);
       }).catch(function(err) {
         this.setState({ error: err });
       }.bind(this));
     }
}

并且this.state.image 从文件输入中设置如下:

updateImage: function(evt) {
    this.setState({
      image: evt.target.files[0]
    }, function() {
      console.log('image:', this.state.image);
    });
  },

AWSAPI.uploadImage 看起来像这样:

uploadImage: function(imageData, type, id) {
    var deferred = when.defer();

    request.put(APIUtils.API_ROOT + 'upload/' + type + '/' + id)
    .type('form')
    .send(imageData)
    .end(function(res) {
      if ( !res.ok ) {
        deferred.reject(res.text);
      } else {
        deferred.resolve(APIUtils.normalizeResponse(res));
      }
    });

    return deferred.promise;
  }

最后,文件接收端点如下所示:

exports.upload = function(req, res) {

  req.pipe(req.busboy);

  req.busboy.on('file', function(fieldname, file) {
    console.log('file:', fieldname, file);
    res.status(200).send('Got a file!');
  });

};

目前,接收端点的on('file') 函数永远不会被调用,因此什么也不会发生。以前,我尝试过使用 multer 而不是 Busboy 的类似方法,但没有更多成功(req.body 包含解码的图像文件,req.files 为空)。

我在这里遗漏了什么吗?将文件从 (ReactJS) Javascript 应用程序上传到 Express API 端点的最佳方法是什么?

【问题讨论】:

  • 你试过socket.io吗?可以用来传输二进制数据和jsons
  • @DmitryMatveev 我认为 socket.io 只是因为不幸地将一些 JSON/文件从客户端发送到服务器而有点矫枉过正。我真的不需要所有的实时功能
  • 您使用的是什么前端。如果不是那么具体,你可以试试jQuery Form plugin。它发出必要的事件,如 beforeSubmituploadProgresssuccesserror。服务器端,可以使用Node Formidable

标签: javascript node.js express reactjs


【解决方案1】:

我认为 superAgent 设置了错误的内容类型 application/x-form-www-encoded 而不是 multipart/form-data 您可以使用 attach 方法来解决这个问题,如下所示:

request.put(APIUtils.API_ROOT + 'upload/' + type + '/' + id)
    .attach("image-file", this.state.image, this.state.image.name)
    .end(function(res){
        console.log(res);
    });

有关附加方法的更多信息,请阅读此处的文档:http://visionmedia.github.io/superagent/#multipart-requests

因为这涉及到一个 nodejs 服务器脚本,所以我决定创建一个 GitHub 存储库而不是小提琴:https://github.com/furqanZafar/reactjs-image-upload

【讨论】:

    【解决方案2】:

    根据经验,当您使用FormData 时,使用 ajax 上传文件是可行的,但是该文件必须是唯一的表单字段/数据。如果你尝试将它与其他数据(如用户名、密码或几乎任何东西)结合起来,它就不起作用。 (可能有解决这个问题的方法,但我不知道)

    如果您需要发送用户名/密码,如果可以的话,您应该将它们作为标题发送。

    我采取的另一种方法是首先使用普通数据进行用户注册,然后在成功后我单独上传带有 FormData 的文件作为更新。

    【讨论】:

    • 这实际上是我最初采用的方法。 JSON 被发送和处理得很好,但是一旦我进入图像上传步骤,req.files 仍然是空的(文件实际上在req.body 中作为一堆 unicode)。
    • 我的意思是从客户端...req.files 听起来像客户端实体
    • 我通过 ajax 从客户端上传它们,但它们被发送到 Express 端点,这是 req.body 发挥作用的地方。
    • 在这种情况下,您可能会受到影响 - stackoverflow.com/questions/23114374/…
    【解决方案3】:

    react 文件上传 iamges 组件:

      class ImageUpload extends React.Component {
        constructor(props) {
          super(props);
          this.state = {file: '',imagePreviewUrl: ''};
        }
    
      _handleSubmit(e) {
        e.preventDefault();
        // this.uploadImage()
        // TODO: do something with -> this.state.file
        console.log('handle uploading-', this.state.file);    }
    
       _handleImageChange(e) {
         e.preventDefault();
    
        let reader = new FileReader();
        let file = e.target.files[0];
    
        reader.onloadend = () => {
          this.setState({
            file: file,
            imagePreviewUrl: reader.result
          });
        }
    
        reader.readAsDataURL(file)   }
    
           // XHR/Ajax file upload     uploadImage(imageFile) {
        return new Promise((resolve, reject) => {
          let imageFormData = new FormData();
    
          imageFormData.append('imageFile', imageFile);
    
          var xhr = new XMLHttpRequest();
    
          xhr.open('post', '/upload', true);
    
          xhr.onload = function () {
            if (this.status == 200) {
              resolve(this.response);
            } else {
              reject(this.statusText);
            }
          };
    
           xhr.send(imageFormData);
    
         });    }
    
      render() {
        let {imagePreviewUrl} = this.state;
        let $imagePreview = null;
        if (imagePreviewUrl) {
          $imagePreview = (<img src={imagePreviewUrl} />);
        } else {
          $imagePreview = (<div className="previewText">Please select an Image for Preview</div>);
        }
    
        return (
          <div className="previewComponent">
            <form onSubmit={(e)=>this._handleSubmit(e)}>
              <input className="fileInput" type="file" onChange={(e)=>this._handleImageChange(e)} />
              <button className="submitButton" type="submit" onClick={(e)=>this._handleSubmit(e)}>Upload Image</button>
            </form>
            <div className="imgPreview">
              {$imagePreview}
            </div>
          </div>
        )   } }    React.render(<ImageUpload/>, document.getElementById("mainApp"));
    

    服务器端图像保存和复制:

    除了 express 你还需要 npm install 'multiparty'。本示例使用多方解析表单数据并提取图像文件信息。然后 'fs' 将临时上传的图片复制到更永久的位置。

    let multiparty = require('multiparty');
    let fs = require('fs');
    
    function saveImage(req, res) {
      let form = new multiparty.Form();
    
      form.parse(req, (err, fields, files) => {
    
        let {path: tempPath, originalFilename} = files.imageFile[0];
        let newPath = "./images/" + originalFilename;
    
        fs.readFile(tempPath, (err, data) => {
          // make copy of image to new location
          fs.writeFile(newPath, data, (err) => {
            // delete temp image
            fs.unlink(tempPath, () => {
              res.send("File uploaded to: " + newPath);
            });
          }); 
        }); 
      })
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-26
      • 2021-11-03
      • 1970-01-01
      • 2020-07-24
      • 2021-02-13
      • 2018-03-28
      • 2020-12-25
      • 1970-01-01
      • 2019-10-14
      相关资源
      最近更新 更多