我正在尝试将图像上传到s3存储桶,但显示以下错误。我正在使用React和DRF。
我正在关注this tutorial。在那里,他们建议先从后端生成签名的URL,然后在签名的URL的帮助下从响应发出请求到s3服务器以上传图像。
Traceback:
File "/app/.heroku/python/lib/python3.7/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/app/.heroku/python/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "/app/.heroku/python/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/app/.heroku/python/lib/python3.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)
File "/app/.heroku/python/lib/python3.7/site-packages/django/views/generic/base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "/app/.heroku/python/lib/python3.7/site-packages/rest_framework/views.py" in dispatch
497. response = self.handle_exception(exc)
File "/app/.heroku/python/lib/python3.7/site-packages/rest_framework/views.py" in handle_exception
457. self.raise_uncaught_exception(exc)
File "/app/.heroku/python/lib/python3.7/site-packages/rest_framework/views.py" in raise_uncaught_exception
468. raise exc
File "/app/.heroku/python/lib/python3.7/site-packages/rest_framework/views.py" in dispatch
494. response = handler(request, *args, **kwargs)
File "/app/articles/api/views.py" in get
82. ExpiresIn=3600
File "/app/.heroku/python/lib/python3.7/site-packages/botocore/signers.py" in generate_presigned_post
688. {'Bucket': bucket}, operation_model)
File "/app/.heroku/python/lib/python3.7/site-packages/botocore/validate.py" in serialize_to_request
297. raise ParamValidationError(report=report.generate_report())
Exception Type: ParamValidationError at /api/blog/api/create-permission/aws-s3/
Exception Value: Parameter validation failed:
Invalid type for parameter Bucket, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
Request information:
USER: XXXder
GET:
image_name = 'asd_adasd_thumb.jpg'
POST: No POST data
FILES: No FILES data
settings.py
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = 'ap-south-1'
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
我如何生成signed_url
import os
import datetime
import boto3
import mimetypes
s3 = boto3.client('s3', config=Config(signature_version='s3v4'))
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},
{"x-amz-algorithm": "AWS4-HMAC-SHA256"}
],
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
const type = image.type
axios.get('https://abc-abc.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();
var key
for (key in res.data.signed_url.fields) {
postData.append(key, res.data.signed_url.fields[key]);
}
postData.append('file', image);
////////// Here I'm sending request to s3//////////////////////
return axios.post(res.data.signed_url.url, postData);
})
.then((res) => {
dispatch({
type: GET_PARTICULAR_BLOG_IMG_UPLOAD_AWS,
payload: res.data
});
})
.catch(err => {
//dispatch(returnErrors(err.response.data, err.response.status));
console.log(err)
dispatch({
type: GET_PARTICULAR_BLOG_IMG_UPLOAD_FAIL
});
});
};
这是表格
fileSelectHandler = event => {
const files = document.getElementById("file_input").files;
const file = files[0]
if (!file) {
return alert("Please select Image")
}
this.props.getSignedRequest(file)
}
<Form onSubmit={this.handleSubmit} className='blog_form' encType="multipart/form-data" method='POST'>
<input className="upload" type="file" accept='image/*' name='image' onChange={this.fileSelectHandler} id="file_input" />
<Button type="primary" htmlType='submit' className="BlogButton">Create Blog</Button>
</Form>
已编辑:
当我从本地主机尝试时,它似乎正在生成签名的URL Please check this screenshot
但是响应状态(来自s3)为204 Please check this images
从本地主机正常运行,将图像上传到s3。但是当我将其部署到heroku时却没有。从heroku尝试时,出现了上面提到的相同错误。
答案 0 :(得分:0)
如错误所示,传递给参数Bucket的值为'None',这是无效值。
Exception Value: Parameter validation failed:
Invalid type for parameter Bucket, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
您正在从系统环境中读取存储桶名称
s3_bucket = os.environ.get('AWS_STORAGE_BUCKET_NAME')
在heroku环境中可能未设置。
如果环境中不存在密钥,则os.environ.get函数将返回None。