我正在遵循这个课程,我认为我做的一切都是正确的,但它给了我
POST https://fakebucket.s3-eu-north-1.amazonaws.com/ 400(错误请求)
views.py
class FilePolicyAPI(APIView):
"""
This view is to get the AWS Upload Policy for our s3 bucket.
What we do here is first create a FileItem object instance in our
Django backend. This is to include the FileItem instance in the path
we will use within our bucket as you'll see below.
"""
permission_classes = [permissions.IsAuthenticated]
authentication_classes = [authentication.SessionAuthentication]
def post(self, request, *args, **kwargs):
"""
The initial post request includes the filename
and auth credientails. In our case, we'll use
Session Authentication but any auth should work.
"""
filename_req = request.data.get('filename')
if not filename_req:
return Response({"message": "A filename is required"}, status=status.HTTP_400_BAD_REQUEST)
policy_expires = int(time.time()+5000)
user = request.user
username_str = str(request.user.username)
"""
Below we create the Django object. We'll use this
in our upload path to AWS.
Example:
To-be-uploaded file's name: Some Random File.mp4
Eventual Path on S3: <bucket>/username/2312/2312.mp4
"""
file_obj = Post.objects.create(
author = request.user,
title=filename_req
)
file_obj_id = file_obj.id
upload_start_path = "{username}/".format(
username = username_str,
file_obj_id=file_obj_id
)
_, file_extension = os.path.splitext(filename_req)
filename_final = "{file_obj_id}{file_extension}".format(
file_obj_id= file_obj_id,
file_extension=file_extension
)
"""
Eventual file_upload_path includes the renamed file to the
Django-stored FileItem instance ID. Renaming the file is
done to prevent issues with user generated formatted names.
"""
final_upload_path = "{upload_start_path}{filename_final}".format(
upload_start_path=upload_start_path,
filename_final=filename_final,
)
if filename_req and file_extension:
"""
Save the eventual path to the Django-stored FileItem instance
"""
file_obj.existingPath = final_upload_path
file_obj.save()
policy_document_context = {
"expire": policy_expires,
"bucket_name": AWS_UPLOAD_BUCKET,
"key_name": "",
"acl_name": "private",
"content_name": "",
"content_length": 524288000,
"upload_start_path": upload_start_path,
}
policy_document = """
{"expiration": "2019-01-01T00:00:00Z",
"conditions": [
{"bucket": "%(bucket_name)s"},
["starts-with", "$key", "%(upload_start_path)s"],
{"acl": "%(acl_name)s"},
["starts-with", "$Content-Type", "%(content_name)s"],
["starts-with", "$filename", ""],
["content-length-range", 0, %(content_length)d]
]
}
""" % policy_document_context
aws_secret = str.encode(AWS_UPLOAD_SECRET_KEY)
policy_document_str_encoded = str.encode(policy_document.replace(" ", ""))
url = 'https://{bucket}.s3-{region}.amazonaws.com'.format(
bucket=AWS_UPLOAD_BUCKET,
region=AWS_UPLOAD_REGION
)
policy = base64.b64encode(policy_document_str_encoded)
signature = base64.b64encode(hmac.new(aws_secret, policy, hashlib.sha1).digest())
data = {
"policy": policy,
"signature": signature,
"key": AWS_UPLOAD_ACCESS_KEY_ID,
"file_bucket_path": upload_start_path,
"file_id": file_obj_id,
"filename": filename_final,
"url": url,
"username": username_str,
}
return Response(data, status=status.HTTP_200_OK)
和jquery:
$(document).ready(function(){
// setup session cookie data. This is Django-related
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// end session cookie data setup.
// declare an empty array for potential uploaded files
var fileItemList = []
// auto-upload on file input change.
$(document).on('change','.cfeproj-upload-file', function(event){
var selectedFiles = $(this).prop('files');
formItem = $(this).parent()
$.each(selectedFiles, function(index, item){
var myFile = verifyFileIsImageMovieAudio(item)
if (myFile){
uploadFile(myFile)
} else {
// alert("Some files are invalid uploads.")
}
})
$(this).val('');
})
function verifyFileIsImageMovieAudio(file){
// verifies the file extension is one we support.
var extension = file.name.split('.').pop().toLowerCase(); //file.substr( (file.lastIndexOf('.') +1) );
switch(extension) {
case 'jpg':
case 'png':
case 'gif':
case 'jpeg':
return file
case 'mov':
case 'mp4':
return file
default:
notAllowedFiles.push(file)
return null
}
};
function constructFormPolicyData(policyData, fileItem) {
var contentType = fileItem.type != '' ? fileItem.type : 'application/octet-stream'
var url = policyData.url
var filename = policyData.filename
var repsonseUser = policyData.user
// var keyPath = 'www/' + repsonseUser + '/' + filename
var keyPath = policyData.file_bucket_path
var fd = new FormData()
fd.append('key', keyPath + filename);
fd.append('acl','private');
fd.append('Content-Type', contentType);
fd.append("AWSAccessKeyId", policyData.key)
fd.append('Policy', policyData.policy);
fd.append('filename', filename);
fd.append('Signature', policyData.signature);
fd.append('file', fileItem);
return fd
}
function fileUploadComplete(fileItem, policyData){
data = {
uploaded: true,
fileSize: fileItem.size,
file: policyData.file_id,
}
$.ajax({
method:"POST",
data: data,
url: "/api/files/complete/",
success: function(data){
displayItems(fileItemList)
},
error: function(jqXHR, textStatus, errorThrown){
alert("An error occured, please refresh the page.")
}
})
}
function displayItems(fileItemList){
var itemList = $('.item-loading-queue')
itemList.html("")
$.each(fileItemList, function(index, obj){
var item = obj.file
var id_ = obj.id
var order_ = obj.order
var html_ = "<div class=\"progress\">" +
"<div class=\"progress-bar\" role=\"progressbar\" style='width:" + item.progress + "%' aria-valuenow='" + item.progress + "' aria-valuemin=\"0\" aria-valuemax=\"100\"></div></div>"
itemList.append("<div>" + order_ + ") " + item.name + "<a href='#' class='srvup-item-upload float-right' data-id='" + id_ + ")'>X</a> <br/>" + html_ + "</div><hr/>")
})
}
function uploadFile(fileItem){
var policyData;
var newLoadingItem;
// get AWS upload policy for each file uploaded through the POST method
// Remember we're creating an instance in the backend so using POST is
// needed.
$.ajax({
method:"POST",
data: {
filename: fileItem.name
},
url: "/api/files/policy/",
success: function(data){
policyData = data
},
error: function(data){
alert("An error occured, please try again later")
}
}).done(function(){
// construct the needed data using the policy for AWS
var fd = constructFormPolicyData(policyData, fileItem)
// use XML http Request to Send to AWS.
var xhr = new XMLHttpRequest()
// construct callback for when uploading starts
xhr.upload.onloadstart = function(event){
var inLoadingIndex = $.inArray(fileItem, fileItemList)
if (inLoadingIndex == -1){
// Item is not loading, add to inProgress queue
newLoadingItem = {
file: fileItem,
id: policyData.file_id,
order: fileItemList.length + 1
}
fileItemList.push(newLoadingItem)
}
fileItem.xhr = xhr
}
// Monitor upload progress and attach to fileItem.
xhr.upload.addEventListener("progress", function(event){
if (event.lengthComputable) {
var progress = Math.round(event.loaded / event.total * 100);
fileItem.progress = progress
displayItems(fileItemList)
}
})
xhr.upload.addEventListener("load", function(event){
console.log("Complete")
// handle FileItem Upload being complete.
// fileUploadComplete(fileItem, policyData)
})
xhr.open('POST', policyData.url , true);
xhr.send(fd);
})
}});
我的代码与教程中的代码几乎相同,我只是复制粘贴它,它已经让我吃了三天了。 我尝试使用 CORS 标头,ive
CORS_ALLOW_ALL_ORIGINS = True CORS_ALLOW_CREDENTIALS = True
我遇到了同样的问题,据我所知,在检查控制台后,我遇到了:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidRequest</Code>
<Message>The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.</Message>
<RequestId>.../RequestId>
<HostId>...</HostId>
</Error>
这似乎与这篇文章有关:不支持您提供的授权机制。请使用AWS4-HMAC-SHA256
我相信这是您使用的区域需要 S4 签名的结果。我将详细说明我如何尽快自行解决问题,但希望这是一个开始!