javascript - 如何在反应中将文件数据转换为二进制数据?
问题描述
我实现了文件上传,其中文件与一些数据一起传递到后端。文件和数据必须编码为表单数据。
我通过两种方式实现了上传:
- formdata 将文件包含为二进制字符串
- formdata 包含文件作为普通字符串(链接到文件)
第一个选项适用于我并且文件已成功上传,而在第二种情况下会出现错误消息:
“提交的数据不是文件。请检查表单上的编码类型。”
1.文件上传,音频文件为二进制字符串(工作)
Form Data
audio: (binary)
title: Some Title
content: Some content
1. 以二进制音频文件创建表单数据的函数和表单(Working)
export class CreateStory extends Component {
state = {
title: "",
content:"",
audio:""
};
static propTypes = {
addStory: PropTypes.func.isRequired
};
// Use Ref to clear uncontrolled file field
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
onChange = (e) => {
if(e.target.name === 'audio') {
this.setState({
[e.target.name]: e.target.files[0]
}, () => console.log(this.state.audio))
} else {
this.setState({
[e.target.name]: e.target.value
}, () => console.log(this.state))
}
}
onSubmit = e => {
e.preventDefault();
let { title, content, audio} = this.state;
let formDataStory = new FormData(); // create form formData
formDataStory.append('audio', audio); // add audio to formData
formDataStory.append('title', title); // add title to formData
formDataStory.append('content', content); // add content to formData
console.log (this.formDataStory);
this.props.addStory(formDataStory) // call addStory function with formDataStory as Input to create new Story
.then(() => {
this.setState({
title: "", // clear title field after submission
content:"", // clear content field after submission
});
this.inputRef.current.value = ''; // clear file field after submission
})
};
render() {
const {title, content, audio} = this.state;
return (
<div className="card card-body mt-4 mb-4">
<h2>Add Story</h2>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Title</label>
<input
className="form-control"
type="text"
name="title"
onChange={this.onChange}
value={title}
/>
</div>
<div className="form-group">
<label>Content</label>
<input
className="form-control"
type="text"
name="content"
onChange={this.onChange}
value={content}
/>
</div>
<div className="form-group">
<label>Audio</label>
<input
className="form-control"
type="file"
name="audio"
onChange={this.onChange}
ref={this.inputRef} // refer to ref
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</form>
</div>
);
}
}
export default connect(
null,
{ addStory }
)(CreateStory);
2.以音频文件为链接的文件上传(不工作)
Form Data
audio: C:\Users\Some Link
title: Some Title
content: Some content
2.以音频文件为链接创建表单数据的功能和表单(不工作)
export class EditStory extends Component {
constructor(props) {
super(props);
this.getStory = this.getStory.bind(this);
this.updateStory = this.updateStory.bind(this);
this.onChangeTitle = this.onChangeTitle.bind(this);
this.onChangeContent=this.onChangeContent.bind(this);
this.onChangeAudio=this.onChangeAudio.bind(this);
this.inputRef = React.createRef();
this.state = {
story: {
id: null,
title: "",
content: "",
audio: ""
}
};
}
componentDidMount() {
this.getStory(this.props.match.params.id);
}
onChangeTitle(e) {
const title = e.target.value;
this.setState(prevState => ({
story: {
...prevState.title,
title: title
}
}), () => console.log(this.state));
}
onChangeContent(e) {
const content = e.target.value;
this.setState(prevState => ({
story: {
...prevState.story,
content: content
}
}), () => console.log(this.state));
}
onChangeAudio(e) {
const audio = e.target.name;
this.setState({
[e.target.name]: e.target.files[0]
}, () => console.log(this.state.audio))
}
getStory(id) {
this.props.getSingleStory(id)
.then(response => {
this.setState({
story: response.data
});
})
.catch(e => {
console.log(e);
});
}
updateStory() {
let id = this.state.story.id;
let title = this.state.story.title;
let content = this.state.story.content;
let audio = this.state.story.audio;
let UpdatedData = new FormData();
UpdatedData.append('id', id);
UpdatedData.append('audio', audio); // add audio to formData
UpdatedData.append('title', title); // add title to formData
UpdatedData.append('content', content);
console.log (id);
console.log (UpdatedData);
this.props.editStory(
id,
UpdatedData
)
.then(response => {
console.log(response.data);
})
.catch(e => {
console.log(e);
});
}
static propTypes = {
getSingleStory: PropTypes.func.isRequired,
editStory: PropTypes.func.isRequired
};
render() {
const {story} = this.state;
return (
<div>
<h1>Edit {story.title}</h1>
<div className="form-group">
<label>Title</label>
<input type="text" name="title" defaultValue={story.title} onChange={this.onChangeTitle} className="form-control" />
</div>
<div className="form-group">
<label>Content</label>
<textarea name="content" rows="5" defaultValue={story.content} onChange={this.onChangeContent} className="form-control" />
</div>
<div className="form-group">
<label>Audio</label>
<input
className="form-control"
type="file"
name="audio"
onChange={this.onChangeAudio}
ref={this.inputRef} // refer to ref
/>
</div>
<div className="btn-group">
<button type="submit" onClick={this.updateStory} className="btn btn-dark">Update</button>
<button type="button" className="btn btn-secondary">Cancel</button>
</div>
</div>
);
}
}
我不明白为什么在第二种情况下音频文件没有编码为二进制字符串。如何在第二种情况下将音频文件转换为二进制字符串并将它们添加到我的表单数据中?
解决方案
这不是一个真正的最小可重复示例,问题是 1.6 岁,但没有答案,所以......
此展开表达式使用标题而不是故事,因此它会擦除其他变量
story: { ...prevState.title,
这会设置 state.audio,忽略 state.story 中获取的值
this.setState({ [e.target.name]: e.target.files[0]
但编码值为 state.story.audio
let audio = this.state.story.audio;
推荐阅读
- javascript - Django:没有提交按钮的表单导致 404 错误
- mysql - Moodle Baracuda check bypass or highest antelope version
- kubernetes-helm - helm given random name replace by another
- string - 如何在 Windows 批处理文件中使用 FOR 获取文本文件中的路径变量?
- mysql - 带有 SUBQUERY 的 MYSQL DELETE 给出错误代码:1235
- android - 在 android 应用程序侧的 Firefox 浏览器中打开 HTML 页面。
- javascript - 在谷歌地图上添加多个标记
- oracle11g - 如何使用 Group by 子句简化 SQL 内部联接以提高 Oracle 的性能
- python - f.tell() 返回一个过高的数字
- node.js - How to test my node/express app is making an API call (through axios)