首页 > 解决方案 > 如何在反应中将文件数据转换为二进制数据?

问题描述

我实现了文件上传,其中文件与一些数据一起传递到后端。文件和数据必须编码为表单数据。

我通过两种方式实现了上传:

  1. formdata 将文件包含为二进制字符串
  2. 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>
    );
  }
}

我不明白为什么在第二种情况下音频文件没有编码为二进制字符串。如何在第二种情况下将音频文件转换为二进制字符串并将它们添加到我的表单数据中?

标签: javascriptreactjsmultipartform-databinaryfiles

解决方案


这不是一个真正的最小可重复示例,问题是 1.6 岁,但没有答案,所以......

  1. 此展开表达式使用标题而不是故事,因此它会擦除其他变量

    story: {
        ...prevState.title,
    
  2. 这会设置 state.audio,忽略 state.story 中获取的值

    this.setState({
        [e.target.name]: e.target.files[0]
    

    但编码值为 state.story.audio

    let audio = this.state.story.audio;
    

推荐阅读