0

我是 ReactJS 和 AWS 的新手。我想用一个简单的按钮创建一个简单的 ReactJS 前端,通过与 Lambda 函数集成的 API 网关将图像上传到 S3(lambda 函数为文件上传创建预签名的 url)。我遇到了 CORS 错误,我已经尝试了我在网上找到的所有内容,但似乎没有任何效果。我想要实现的主要目标是将图像上传到 S3 并获取图像的 url 以将其发布到 DynamoDB 表中作为参考。我不确定如何使所有这些组件一起工作。我关注了这篇文章:https ://blog.webiny.com/upload-files-to-aws-s3-using-pre-signed-post-data-and-a-lambda-function-7a9fb06d56c1

这是我的 Lambda 代码:

const S3 = require("aws-sdk/clients/s3");
const uniqid = require("uniqid");
const mime = require("mime");

/**
 * Use AWS SDK to create pre-signed POST data.
 * We also put a file size limit (100B - 10MB).
 * @param key
 * @param contentType
 * @returns {Promise<object>}
 */
const createPresignedPost = ({ key, contentType }) => {
const s3 = new S3();
const params = {
  Expires: 60,
  Bucket: "uploadimage",
  Conditions: [["content-length-range", 100, 3000000]], // 100Byte - 3MB
  Fields: {
    "Content-Type": contentType,
    key
  }
};

return new Promise(async (resolve, reject) => {
s3.createPresignedPost(params, (err, data) => {
  if (err) {
    reject(err);
    return;
  }
  resolve(data);
});
});
};

/**
 * We need to respond with adequate CORS headers.
 * @type {{"Access-Control-Allow-Origin": string, "Access-Control-Allow-Credentials": boolean}}
 */
const headers = {
 "Access-Control-Allow-Origin": "*",
 "Access-Control-Allow-Credentials": true
};

module.exports.getPresignedPostData = async ({ body }) => {
  try {
    const { name } = JSON.parse(body);
    const presignedPostData = await createPresignedPost({
      key: `${uniqid()}_${name}`,
      contentType: mime.getType(name)
    });

return {
  statusCode: 200,
  headers,
  body: JSON.stringify({
    error: false,
    data: presignedPostData,
    message: null
  })
};
} catch (e) {
 return {
   statusCode: 500,
   headers,
   body: JSON.stringify({
     error: true,
     data: null,
     message: e.message
   })
 };
}
};

我创建了启用了 lambda 代理集成功能的 AWS API,以确保从此处传递标头以避免 CORS 错误,但它仍然以某种方式显示它们。

我的 ReactJS 前端组件代码如下所示(取自上面链接的教程):

import React from "react";
import Files from "react-butterfiles";

function Upload() {
  /**
   * Retrieve pre-signed POST data from a dedicated API endpoint.
   * @param selectedFile
   * @returns {Promise<any>}
   */
  const getPresignedPostData = (selectedFile) => {
    return new Promise((resolve) => {
      const xhr = new XMLHttpRequest();

      // Set the proper URL here.
      const url = "https://xyz---.amazonaws.com/Upload/";

      xhr.open("POST", url, true);
      xhr.setRequestHeader("Content-Type", "application/json");
      xhr.send(
        JSON.stringify({
          name: selectedFile.name,
          type: selectedFile.type,
        })
      );
      xhr.onload = function () {
        resolve(JSON.parse(this.responseText));
      };
    });
  };

  /**
   * Upload file to S3 with previously received pre-signed POST data.
   * @param presignedPostData
   * @param file
   * @returns {Promise<any>}
   */
  const uploadFileToS3 = (presignedPostData, file) => {
    return new Promise((resolve, reject) => {
      const formData = new FormData();
      Object.keys(presignedPostData.fields).forEach((key) => {
        formData.append(key, presignedPostData.fields[key]);
      });

      // Actual file has to be appended last.
      formData.append("file", file);

      const xhr = new XMLHttpRequest();
      xhr.open("POST", presignedPostData.url, true);
      xhr.send(formData);
      xhr.onload = function () {
        this.status === 204 ? resolve() : reject(this.responseText);
      };
    });
  };

  /**
   * Component renders a simple "Select file..." button which opens a file browser.
   * Once a valid file has been selected, the upload process will start.
   * @returns {*}
   * @constructor
   */
  return (
    <Files
      onSuccess={async ([selectedFile]) => {
        // Step 1 - get pre-signed POST data.
        const { data: presignedPostData } = await getPresignedPostData(
          selectedFile
        );

        // Step 2 - upload the file to S3.
        try {
          const { file } = selectedFile.src;
          await uploadFileToS3(presignedPostData, file);
          console.log("File was successfully uploaded!");
        } catch (e) {
          console.log("An error occurred!", e.message);
        }
      }}
    >
      {({ browseFiles }) => (
        <button onClick={browseFiles}>Select file...</button>
      )}
    </Files>
  );
}

export default Upload;

任何帮助将不胜感激!最终,我想将图像上传到 s3,然后将图像 url 存储在 dynamodb 表中作为参考。谢谢!

4

0 回答 0