reactjs - 如何使用 react 和 django rest 框架将图像上传到 aws s3

标签 reactjs amazon-web-services amazon-s3 redux django-rest-framework

我正在尝试使用 react 和 drf 将图像上传到 aws s3。我正在关注这个 heroku documentation .我收到错误,提示请求失败,状态码为 400。

正如他们首先在链接中建议的那样,我从后端创建了签名 url。

urlpatterns = [ 
   path('api/create-permission/aws-s3/', SignS3Upload.as_view(), name='aws-s3'),    
]

import os
import boto3
import mimetypes
s3 = boto3.client('s3')

class SignS3Upload(APIView):
    # authentication_classes = (authentication.SessionAuthentication,)
    # permission_classes = [IsAuthenticated, ]

    def get(self, request):
        s3_bucket = os.environ.get('AWS_STORAGE_BUCKET_NAME')
        file_name = request.GET['image_name']
        file_type = mimetypes.guess_type(file_name)[0]
        presigned_post = s3.generate_presigned_post(
            Bucket=s3_bucket,
            Key=file_name,
            Fields={"acl": "public-read", "Content-Type": file_type},
            Conditions=[
                {"acl": "public-read"},
                {"Content-Type": file_type}
            ],
            ExpiresIn=3600
        )

        data = {
            "signed_url": presigned_post,
            'url': 'https://%s.s3.amazonaws.com/%s' % (s3_bucket, file_name)
        }
        return Response(data) 

在前端,我使用 React 和 Redux。这里我如何从前端发送请求
export const getSignedRequest = (image) => (dispatch, getState) => {

    const image_name = image.name

    axios.get('https://my-site.herokuapp.com/api/blog/api/create-permission/aws-s3/', { params: { image_name } })
        .then((res) => {
            dispatch({
                type: GET_PARTICULAR_BLOG_IMG_UPLOAD,
                payload: res.data
            });


            var postData = new FormData();
            for (key in res.data.fields) {
                postData.append(key, res.data.fields[key]);
            }
            postData.append('file', image_name);

            return axios.post(res.data.url, postData);
        })
        .then((res) => {
            dispatch({
                type: GET_PARTICULAR_BLOG_IMG_UPLOAD_AWS,
                payload: res.data
            });
        })
        .catch((err) => {
            console.log(err)
        });

};

我在前端收到第一个 axios 请求的响应,如下所示
signed_url: {
  url: 'https://my-site.s3.amazonaws.com/',
  fields: {
    acl: 'public-read',
    'Content-Type': 'image/jpeg',
    key: 'xxxxxxxxxxx.jpg',
    AWSAccessKeyId: 'xxx_access_id_xxxx',
    policy: 'xxx_policy_xxx',
    signature: 'xxx_signature_xxx'
  }
},
url: 'https://my-site.s3.amazonaws.com/xxxxxxxxxxx.jpg'

},

这是settings.py
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

最佳答案

我也遇到了同样的问题。这是我给你的修复。
你的后端 django 代码应该是这样的。

import boto3

def create_presigned_url(
    object_name,
    object_type,
    bucket_name=settings.BUCKET_NAME,
    expiration=3600
):


    # Generate a presigned S3 POST URL
    s3_client = boto3.client(
        's3',
        aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
        region_name=settings.AWS_REGION_NAME,
    )

        response = s3_client.generate_presigned_url(
            'put_object',
            {
                'Bucket': bucket_name,
                'Key': object_name,
                'ACL': 'public-read',
                'ContentType': object_type
            },
            ExpiresIn=expiration,
        )
    
    return {
        "signedRequest": response,
        'url': f'https://{bucket_name}.s3.{settings.AWS_REGION_NAME}.amazonaws.com/{object_name}'
    }
对象名称和对象类型是您的请求对象中包含的文件名和文件类型。
您前端的代码应该是这样的
import axios from "axios";

const fileHandler = (file) => {
    let response = await getSignedUrl({
      fileName: file.name,
      fileType: file.type,
    });
    let { signedRequest, url } = response.data || {};

    // fileType in the headers for the upload
    let options = { headers: { "Content-Type": file.type } };

    let instance = axios.create();
    instance.put(signedRequest, file, options);
}
网址 响应对象中的键是在向 signedRequest 发送放置请求后的图像 url

关于reactjs - 如何使用 react 和 django rest 框架将图像上传到 aws s3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58129914/

相关文章:

ruby-on-rails - 使用 Heroku 将 Zip 上传到 S3,upzip 并允许其他人使用唯一链接访问提取的文件

reactjs - 将函数作为 prop 传递,未定义错误

javascript - 子组件在 POST 请求后不重新渲染父组件

reactjs - 如何在 React 中使用 Relax.js?

reactjs - @material-ui/icons 中图标的替代方案

amazon-web-services - 使用 s3fs 实用程序 AWS 安装 S3 存储桶

amazon-web-services - 如何终止在远程 aws 服务器的端口中运行的进程

类似 Heroku 的 Amazon EC2

django - 当部署 Django 应用程序 (`python manage.py collectstatic` 不起作用时,如何向 AWS 提供静态文件)?

ruby-on-rails - 如何在 Paperclip 和 Rails 中使用多个 S3 帐户