admin管理员组文章数量:1297120
In the application I'm currently working on, there are a couple of file forms that are submitted via superagent
to an Express API endpoint. For example, image data is posted like so:
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));
}
}
and this.state.image
is set like this from a file input:
updateImage: function(evt) {
this.setState({
image: evt.target.files[0]
}, function() {
console.log('image:', this.state.image);
});
},
AWSAPI.uploadImage
looks like this:
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;
}
And lastly, the file receiving endpoint looks like this:
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!');
});
};
Currently, the receiving endpoint's on('file')
function never gets called and so nothing happens. Previously, I've tried similar approaches with multer instead of Busboy with no more success (req.body
contained the decoded image file, req.files
was empty).
Am I missing something here? What is the best approach to upload files from a (ReactJS) Javascript app to an Express API endpoint?
In the application I'm currently working on, there are a couple of file forms that are submitted via superagent
to an Express API endpoint. For example, image data is posted like so:
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));
}
}
and this.state.image
is set like this from a file input:
updateImage: function(evt) {
this.setState({
image: evt.target.files[0]
}, function() {
console.log('image:', this.state.image);
});
},
AWSAPI.uploadImage
looks like this:
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;
}
And lastly, the file receiving endpoint looks like this:
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!');
});
};
Currently, the receiving endpoint's on('file')
function never gets called and so nothing happens. Previously, I've tried similar approaches with multer instead of Busboy with no more success (req.body
contained the decoded image file, req.files
was empty).
Am I missing something here? What is the best approach to upload files from a (ReactJS) Javascript app to an Express API endpoint?
Share Improve this question edited Nov 20, 2014 at 18:30 Jakemmarsh asked Nov 20, 2014 at 17:16 JakemmarshJakemmarsh 4,67112 gold badges44 silver badges71 bronze badges 3- did u try socket.io? it can be used to transmit binary data and jsons – Dmitry Matveev Commented Nov 20, 2014 at 17:51
- @DmitryMatveev I think socket.io would be a little overkill just for sending some JSON/files from client to server unfortunately. I don't really need all the real-time features – Jakemmarsh Commented Nov 20, 2014 at 18:00
- What frontend are you using. If not so specific, you can give it a try for jQuery Form plugin. It emits necessary events like beforeSubmit, uploadProgress, success, error. Server side, you can use Node Formidable. – Palak Bhansali Commented Dec 5, 2014 at 7:36
3 Answers
Reset to default 7 +50I think superAgent is setting the wrong content-type of application/x-form-www-encoded
instead of multipart/form-data
you can fix this by using the attach method like so:
request.put(APIUtils.API_ROOT + 'upload/' + type + '/' + id)
.attach("image-file", this.state.image, this.state.image.name)
.end(function(res){
console.log(res);
});
for more information about the attach method, read the documentation here: http://visionmedia.github.io/superagent/#multipart-requests
since this involves a nodejs server script I decided to make a GitHub repo instead of a fiddle: https://github./furqanZafar/reactjs-image-upload
From experience, uploading a file using ajax works when you use FormData
, however the file must be the only form field / data. If you try and bine it with other data (like username, password or pretty much anything at all) it does not work. (Possibly there are work arounds to get around that issue, but I am not aware of any)
If you need to send the username/password you should be sending those as headers if you can instead.
Another approach I took was first do the user registration with the normal data, then on success I upload the file with the FormData separately as an update.
The react file upload iamges ponent:
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"));
The Server Side Image Save and Copy:
Along with express You needed to npm install 'multiparty'. This example uses multiparty to parse the form data and extract the image file information. Then 'fs' to copy the temporarily upload image to a more permanent location.
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);
});
});
});
})
}
本文标签: javascriptHow to upload files from ReactJS to Express endpointStack Overflow
版权声明:本文标题:javascript - How to upload files from ReactJS to Express endpoint - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741642781a2390014.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论