我已经成功设置了存储桶并将静态文件传输到Amazon S3。
但是,当我尝试加载S3文件时,收到403禁止消息。
这是我的settings.py文件中的内容:
# AWS s3 (image storage)
AWS_ACCESS_KEY_ID = 'XXX' # XXX replaced with the actual key
AWS_SECRET_ACCESS_KEY = 'YYY' # YYY replaced with the actual key
# sensitive data will be replaced with environment variables when page is public
AWS_STORAGE_BUCKET_NAME = 'diceart-static'
AWS_S3_CUSTOM_DOMAIN = 's3.eu-west-2.amazonaws.com/%s' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = None
AWS_BUCKET_ACL = None
AWS_QUERYSTRING_AUTH = False
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
所以当我跑步
python manage.py collectstatic
一切正常!而且我可以看到所有上传到Amazon S3的文件。我还可以看到对此进行程序化访问的时间,所以我知道这一切都可行。
这是我希望提供S3文件的html模板文件的内容:
{% extends 'dice/base.html' %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{% if not uploaded_file_url %}
<button type="submit" class="btn btn-success mt-2">Upload</button>
{% endif %}
</form>
{% if uploaded_file_url %}
<p>File uploaded at: <a href="{{ uploaded_file_url }}">{{ uploaded_file_url }}</a></p>
<img src="{{ uploaded_file_url }}">
{% endif %}
<p><a href="{% url 'index' %}">Return to home</a></p>
<p>Have a picture of a cat:</p>
<p><img src="{% static 'cat.jpg' %}"></p>
{% endblock %}
关键是倒数第二行:
<p><img src="{% static 'cat.jpg' %}"></p>
上面的代码与用户文件上传有关,我暂时不使用S3。
现在,当页面加载时,它不会出现错误,并且相关行显示如下:
<img src="https://s3.eu-west-2.amazonaws.com/diceart-static/static/cat.jpg">
并对照我的S3存储桶检查它是否匹配:
https://s3.eu-west-2.amazonaws.com/diceart-static/static/cat.jpg
但是我收到403禁止错误并且没有图像加载。
这是我在Chrome开发人员工具网络标题中看到的内容:
Request URL: https://s3.eu-west-2.amazonaws.com/diceart-static/static/cat.jpg
Request Method: GET
Status Code: 403 Forbidden
Remote Address: 52.95.148.64:443
Referrer Policy: no-referrer-when-downgrade
Provisional headers are shown
Referer: https://mysubdomain.pythonanywhere.com/upload2/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
引荐来源网址是加载图像的页面,该页面托管在Pythonanywhere上。
现在我不确定S3存储桶的网址。我在网上检查的所有地方似乎都有结构
https://diceart-static.s3.amazonaws.com
而不是我拥有的东西
https://s3.eu-west-2.amazonaws.com/diceart-static
我认为这可能只是对AWS网址结构的更改,而不是我的上传正常工作时出现的问题,但这也许值得一提。
因此,从本质上讲,我可以编程方式上传,但无法使用django-storages和boto3查看我的S3文件。我在这里想念什么?
请注意,存储桶不允许公共访问,但是我无法更改此设置,因为Amazon不允许我(?!)。我认为这并不重要,因为我在此处输入了凭据,我认为这些凭据将作为标头发送给我,以供访问。
答案 0 :(得分:0)
在上述设置中, AWS_DEFAULT_ACL 设置为无, doc说
如果设置为无,则所有文件都将继承存储桶的ACL。
,S3的默认ACL为私有。
您可以按照建议设置AWS_DEFAULT_ACL = None
,然后通过继承S3Boto3Storage
来编写自己的存储类:
#myapp/myfilestorage.py
from storages.backends.s3boto3 import S3Boto3Storage
from django.conf import settings
class StaticS3Storage(S3Boto3Storage):
location = settings.AWS_STATIC_LOCATION
default_acl = 'public-read'
那么您在我们的设置中也有此设置:
AWS_STATIC_LOCATION = 'static'
STATICFILES_STORAGE = 'myapp.myfilestorage.StaticS3Storage'
您也可以视情况编辑/复制 DEFAULT_FILE_STORAGE
答案 1 :(得分:0)
我认为该文章已过时,因此有点误导。 django-storages
文档不是很好,但是经过反复试验,我认为您真正想要的设置是:
AWS_ACCESS_KEY_ID = '<enter key>'
AWS_SECRET_ACCESS_KEY = '<enter key>'
AWS_STORAGE_BUCKET_NAME = 'diceart-static'
AWS_S3_REGION_NAME = 'eu-west-2'
AWS_DEFAULT_ACL = None
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
请注意,我已经从设置中删除了AWS_S3_CUSTOM_DOMAIN
和STATIC_URL
。这些将由django-storages
自动为您构建。
使用这些设置,您仍然应该能够将存储桶权限保留为不公开,并且由于使用了查询字符串身份验证,它仍然可以正常工作。
尽管上述方法可行,但我不确定这对于公共Web应用程序来说是“最佳实践”。如果您能够取消选中Block all public access
框并将其关闭,则可以改用这些设置,而不会使用(或不需要)querystring auth。
# ... same as above
# Make default ACL publicly readable
AWS_DEFAULT_ACL = 'public-read'
# Turn off query auth, although not sure this is needed.
AWS_QUERYSTRING_AUTH = False
# ... same as above