【问题标题】:Can't upload file to firebase storage无法将文件上传到 Firebase 存储
【发布时间】:2019-11-06 14:19:24
【问题描述】:

我正在尝试将文件上传到 firebase,但文件上传进度达到 100%,然后突然显示一个未知错误,例如

{
  "error": {
    "code": 400,
    "message": "Bad Request. Could not create object",
    "status": "CREATE_OBJECT"
  }
}

这是我用来上传文件的代码,这是完成文件上传的实际组件,用户打开一个模式来选择一个文件,然后在模式中选择并按下发送后文件上传开始在下面的组件中。

import React, { Component } from "react";
import { Segment, Button, Input, ButtonGroup } from "semantic-ui-react";
import firebase from "../../firebase";
import FileModal from "./FileModal";
import uuidv4 from "uuid/v4";

class MessageForm extends Component {
  state = {
    storageRef: firebase.storage().ref(),
    message: "",
    channel: this.props.currentChannel,
    user: this.props.currentUser,
    loading: false,
    errors: [],
    modal: false,
    uploadState: "",
    uploadTask: null,
    percentUploaded: 0
  };

  uploadFile = (file, metadata) => {
    const pathToUpload = this.state.channel.id;
    const ref = this.props.messagesRef;
    const filePath = `chat/public/${uuidv4}.jpg`;

    this.setState(
      {
        uploadState: "uploading",
        uploadTask: this.state.storageRef.child(filePath).put(file, metadata)
      },
      () => {
        this.state.uploadTask.on(
          "state_changed",
          snap => {
            const percentUploaded = Math.round(
              (snap.bytesTransferred / snap.totalBytes) * 100
            );
            this.setState({ percentUploaded });
          },
          err => {
            console.error(err);
            this.setState({
              errors: [...this.state.errors, err],
              uploadState: "error",
              uploadTask: null
            });
          },
          () => {
            console.log(this.state.uploadTask);
            this.state.uploadTask.snapshot.ref
              .getDownloadURL()
              .then(downloadUrl => {
                this.sendFileMessage(downloadUrl, ref, pathToUpload);
              })
              .catch(err => {
                console.error(err);
                this.setState({
                  errors: [...this.state.errors, err],
                  uploadState: "error",
                  uploadTask: null
                });
              });
          }
        );
      }
    );
  };

  sendFileMessage = (fileUrl, ref, pathToUpload) => {
    ref
      .child(pathToUpload)
      .push()
      .set(this.createMessage(fileUrl))
      .then(() => {
        this.setState({
          uploadState: "done"
        }).catch(err => {
          console.error(err);
          this.setState({
            errors: [...this.state.errors, err]
          });
        });
      });
  };

  openModal = () => {
    this.setState({
      modal: true
    });
  };

  closeModal = () => {
    this.setState({
      modal: false
    });
  };

  handleChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  };

  createMessage = (fileUrl = null) => {
    const message = {
      timestamp: firebase.database.ServerValue.TIMESTAMP,
      user: {
        id: this.state.user.uid,
        name: this.state.user.displayName,
        avatar: this.state.user.photoURL
      }
    };
    if (fileUrl != null) {
      message["image"] = fileUrl;
    } else {
      message["content"] = this.state.message.trim();
    }

    return message;
  };

  sendMessage = () => {
    const { messagesRef } = this.props;
    const { message, channel } = this.state;

    if (message) {
      this.setState({
        loading: true
      });
      messagesRef
        .child(channel.id)
        .push()
        .set(this.createMessage())
        .then(() => {
          this.setState({
            loading: false,
            message: "",
            errors: []
          });
        })
        .catch(err => {
          console.error(err);
          this.setState({
            loading: false,
            errors: [...this.state.errors, err]
          });
        });
    } else {
      this.setState({
        errors: [...this.state.errors, { message: "Add a message" }]
      });
    }
  };

  render() {
    const { errors, message, loading, modal } = this.state;
    return (
      <Segment className="message__form">
        <Input
          fluid
          name="message"
          style={{ marginBottom: "0.7em" }}
          icon="add"
          iconPosition="left"
          placeholder="Write your message"
          onChange={this.handleChange}
          className={
            errors.some(error => error.message.includes("message"))
              ? "error"
              : ""
          }
          value={message}
        />
        <ButtonGroup icon widths="2">
          <Button
            onClick={this.sendMessage}
            disabled={loading}
            color="orange"
            content="Add reply"
            labelPosition="left"
            icon="edit"
          />
          <Button
            color="violet"
            content="Upload Media"
            labelPosition="right"
            icon="cloud upload"
            onClick={this.openModal}
          />
          <FileModal
            modal={modal}
            closeModal={this.closeModal}
            uploadFile={this.uploadFile}
          />
        </ButtonGroup>
      </Segment>
    );
  }
}

export default MessageForm;

【问题讨论】:

  • 如果您需要帮助解决此问题,您需要分享更多详细信息,可能包括您用于上传文件的代码以及您已采取的诊断或解决问题的步骤。

标签: javascript reactjs firebase firebase-storage


【解决方案1】:

只是一个猜测,但我怀疑您的错误可能与您在组件的 state 中存储 uploadTask 的方式有关...这让我很不舒服 - 它似乎违反了核心之一在 React 中使用组件状态的原则。

您可能已经听说过只能通过setState 命令改变状态...而您的方法的问题是状态的uploadTask 部分将在上传执行期间发生变异。事实上,您的代码依赖于它 - 您已经编写了它,以便在更新 uploadTask 时,它的百分比会显示在屏幕上。

总体而言,您的想法是正确的 - 只需将 uploadTask: this.state.storageRef.child(filePath).put(file, metadata) 分配从您的 state... 中取出...如下所示:

uploadFile = (file, metadata) => {
    const pathToUpload = this.state.channel.id;
    const ref = this.props.messagesRef;
    const filePath = `chat/public/${uuidv4}.jpg`;

    this.setState(
        {
            uploadState: "uploading",
        },
        () => {
            let uploadTask = this.state.storageRef.child(filePath).put(file, metadata);
            uploadTask.on(
                "state_changed",
                snap => {
                    const percentUploaded = Math.round(
                        (snap.bytesTransferred / snap.totalBytes) * 100
                    );
                    this.setState({ percentUploaded });
                },
                err => {
                    console.error(err);
                    this.setState({
                        errors: [...errors, err],
                        uploadState: "error",
                    });
                },
                () => {
                    console.log(uploadTask);
                    uploadTask.snapshot.ref
                        .getDownloadURL()
                        .then(downloadUrl => {
                            this.sendFileMessage(downloadUrl, ref, pathToUpload);
                        })
                        .catch(err => {
                            console.error(err);
                            this.setState({
                                errors: [...this.state.errors, err],
                                uploadState: "error",
                            });
                        });
                }
            );
        }
    );
};

未经测试的代码,仅限概念

【讨论】:

    猜你喜欢
    • 2021-09-19
    • 2021-12-31
    • 2019-03-28
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    • 2020-11-20
    相关资源
    最近更新 更多