2014-11-20 29 views
3

在我目前工作的應用程序中,有幾個是通過superagent提交給一個Express端點API文件形式。例如,圖像數據發佈,像這樣:如何上傳從ReactJS文件Express端點

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

AWSAPI.uploadImage看起來是這樣的:

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從文件輸入設置這樣

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端點的最佳方法是什麼?

+0

您是否試過[socket.io](http://socket.io/)?它可以用來傳輸二進制數據和jsons – 2014-11-20 17:51:29

+0

@DmitryMatveev我認爲socket。不幸的是,io只是爲了將一些JSON /文件從客戶端發送到服務器而略微矯枉過正。我並不需要所有的實時功能 – Jakemmarsh 2014-11-20 18:00:47

+0

您使用的是什麼前端。如果不是那麼具體,你可以試試[jQuery Form插件](https://github.com/malsup/form/)。它發出必要的事件,例如*提交之前*,* uploadProgress *,*成功*,*錯誤*。服務器端,你可以使用[Node Formidable](https://github.com/felixge/node-formidable)。 – 2014-12-05 07:36:02

回答

7

我覺得SuperAgent的是設置錯了內容類型的「應用程序/ x-形式WWW的編碼」,而不是「多/表單數據」,您可以通過使用附加方法,像這樣解決這個問題:

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

1

從以往的經驗,當你使用FormData使用AJAX的作品上傳文件,但該文件必須是唯一的表單字段/數據。如果您嘗試將其與其他數據(如用戶名,密碼或幾乎任何其他數據)結合使用,則不起作用。 (可能有變通來解決這個問題,但我不知道有任何)

如果您需要發送的用戶名/密碼,您應該發送這些作爲標題,如果你能代替。

我採取的另一種方法是先用正常數據進行用戶註冊,然後成功上傳帶FormData的文件作爲更新。

+0

這實際上是我最初採取的方法。 JSON被髮送並處理得很好,但是一旦我進入圖像上傳步驟,'req.files'仍然是空的(文件實際上在'req.body'內部作爲一組unicode)。 – Jakemmarsh 2014-11-20 17:49:54

+0

我的意思是從客戶端... req.files聽起來像一個客戶端實體 – 2014-11-20 17:53:36

+0

我從客戶端通過ajax上傳它們,但它們被髮送到Express端點,這是'req.body'的來源進場。 – Jakemmarsh 2014-11-20 17:58:11

0

的反應文件上傳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")); 

服務器端圖像存儲和複製:

隨着表達您需要安裝新公共管理「多黨制」。本示例使用多方解析表單數據並提取圖像文件信息。然後'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); 
     }); 
     }); 
    }); 
    }) 
} 
相關問題