S3存储桶,使用axios将图像放置到预签名的url中

时间:2019-12-30 16:53:02

标签: javascript reactjs amazon-s3 axios

我正在研究一个简单的拖放/输入按钮文件上传组件。在以下组件中,通过拖放或输入按钮获取文件:

反应组件1:

import React, {useState, useEffect} from 'react';
import ReactDOM from 'react-dom';

function ReceiptUploadPortal(props) {

  const {element, uploadFile} = props;
  const [errors, setErrors] = useState([]);
  const [dropzoneActive, setDropzoneActive] = useState(false);
  const [file, setFile] = useState();
  const allowedTypes = ['image/jpg', 'image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'application/pdf'];

  useEffect(() => {
    const isValidSize = file && file.size > 6 * 1024;
    const isValidType =  file && allowedTypes.includes(file.type);
    if (isValidSize && isValidType) {
      setErrors([]);
      uploadFile(file);
    } else {
      if (file && !isValidSize) setErrors([...errors, 'file exceeds maximum allowed size']);
      if (file && !isValidType) setErrors([...errors, 'unsupported file type, please use a jpg file extension']);
    }
  }, [file])

  function handleDragOver(event) {
    event.preventDefault();
    setDropzoneActive(true);
    setErrors([]);
  }

  function handleDrop(event) {
    event.preventDefault();
    if (event.dataTransfer.files.length === 1) {
      setFile(event.dataTransfer.files[0]);
    } else {
      setErrors(['too many files, please upload one image at a time'])
    }
    setDropzoneActive(false)
  }

  function handleFileSelect(event) {
    setErrors([]);
    setFile(event.target.files[0]);
  }

  return ReactDOM.createPortal(
    <div className="receipt-upload-widget-container">
      <div className="file-info-wrapper">
        <div className="file-info">
          <span>FILE TYPE</span><br />
          <span>JPG</span>
        </div>
        <div className="file-info">
          <span>MAX SIZE</span><br />
          <span>6 MB</span>
        </div>
      </div>
      <div 
        className={`file-upload-drop-zone ${dropzoneActive ? 'active' : ''}`}
        onDrop={(event) => handleDrop(event)}
        onDragOver={(event) => handleDragOver(event)}>
        <p>
          Drag & Drop<br />
          or upload your image manually
        </p>
      </div>
      <div className="file-input-wrapper">
        <label>
          Upload
          <input 
            type="file"
            accept="image/*"
            onChange={(event) => handleFileSelect(event)} />
        </label>
        <p>{file && file.name}</p>
      </div>
      <div className="fileErrors">
        {errors.map((error, index) => <div className="fileError" key={index}>{error}</div>)}
      </div>
    </div>, element
  );

}

导出默认的ReceiptUploadPortal;

反应组件2:

import React, {useState} from 'react';
import ReceiptUploadPortal from './ReceiptUploadPortal';
import {receiptUpload} from '../../api/FileUploadService';
import NotificationComponent from '../../ui-components/NotificationComponent';
import { successNotification, errorNotification } from '../../helpers/notficationHelper';

function ReceiptUploadContainer() {

  const receiptUploadWidgets = [...document.querySelectorAll(`div[data-widget='ReceiptUpload']`)];

  const [notification, setNotfication] = useState({
    ...successNotification,
    onClosed: () => setNotfication({...notification, show: false})
  });

  async function handleUpload(file) {
    const req = await receiptUpload(file);
    if (req) {
      setNotfication({
        ...notification,
        show: true
      })
    } else {
      setNotfication({
        ...notification,
        ...errorNotification,
        show: true
      });
    }
  }

  return (
    <div id="ReceiptUploadContainer">
      {receiptUploadWidgets.map((element, index) => 
        <ReceiptUploadPortal
          key={index}
          element={element}
          uploadFile={(file) => handleUpload(file)} />
      )}
      <NotificationComponent {...notification}/>
    </div>
  );

}

export default ReceiptUploadContainer

然后这会触发服务被调用,这是发生错误的地方...

服务

import axios from 'axios';
import { urls } from './Urls';
import { getAccountInfo } from './GigyaService';
import { getAWSHeaders } from '../helpers/getAWSHeaders';

export async function receiptUpload(file) {
  const account = await getAccountInfo();
  const headers = getAWSHeaders(account);
  const presignUrl = await axios.post(urls.fileUpload.presignUpload, {fileName: file.name}, {headers}).then(res => res.data);
  const fileUpload = presignUrl && await axios.put(presignUrl.presignUrl, file, {'Content-Type': file.type}).then(res => res.status);
  const fileId = fileUpload && await axios.post(urls.fileUpload.receiptUpload, {file_name: file.name}, {headers}).then(res => res.data);
  const receiptSubmit = fileId && await axios.post(urls.fileUpload.receiptSubmit, {
    id_type: 'third_party_id',
    file_id: fileId.file_id
  }, {headers}).then(res => res.data);
  return receiptSubmit;
}

一切正常,直到我尝试将实际文件发布到S3为止。

意思是,我能够获取预签名的网址。但是,当我上传文件时,收到200响应,没有数据负载,并且在S3中可以看到文件不存在。

这当然会导致接下来的两个请求失败。

对我可能在这里做错的任何想法吗?

0 个答案:

没有答案