#javascript #ajax #amazon-web-services #amazon-s3
#javascript #ajax #amazon-веб-сервисы #amazon-s3
Вопрос:
У меня есть веб-страница, и пока она работает для загрузки одного файла, но мне нужно иметь возможность загружать несколько файлов одновременно. Amazon это не нравится, и он выдает мне «Для отправки POST требуется ровно одна загрузка файла на запрос». Я бы предположил, что мне просто нужно сделать отдельный запрос POST для каждого файла, но я не знаю, как это сделать. Я просто использую простой HTML и ajax и хотел бы придерживаться этого.
@import " '_normalize.css' ";
@import " '_defaults.css' ";
body,
.ad,
.sm {
font-family: Lucida Grande, Helvetica Neue, Helvetica, Arial, Verdana, sans-serif
}
a {
color: currentColor;
text-decoration: none
}
.clearfix::after {
content: '';
display: table;
clear: both
}
.ad {
width: 9.375rem;
color: #444;
color: rgba( 0, 0, 0, .75);
background-color: #fff;
background-color: rgba( 255, 255, 255, .5);
position: fixed;
z-index: 1000;
top: .625rem;
left: .625rem;
padding: .5rem .625rem
}
.ad--dark {
color: #ddd;
color: rgba( 255, 255, 255, .75);
background-color: #111;
background-color: rgba( 0, 0, 0, .5)
}
.ad__close {
width: .625rem;
height: .625rem;
background-color: #777;
background-color: rgba( 0, 0, 0, .5);
border-radius: 50%;
position: absolute;
z-index: 1;
top: -.25rem;
right: -.25rem;
-webkit-transition: -webkit-transform .25s ease-in-out;
transition: transform .25s ease-in-out
}
.ad--dark .ad__close {
background-color: #ddd;
background-color: rgba( 255, 255, 255, .75)
}
.ad__close:hover,
.ad__close:focus {
-webkit-transform: scale( 1.25);
-ms-transform: scale( 1.25);
transform: scale( 1.25)
}
#carbonads {
font-size: .875rem;
letter-spacing: -.071em;
line-height: 1.125rem
}
#carbonads a {
color: currentColor;
display: block;
margin-top: .313rem
}
#carbonads .carbon-poweredby {
font-size: .75rem;
text-transform: uppercase;
color: #aaa;
color: rgba( 0, 0, 0, .25)
}
.ad--dark #carbonads .carbon-poweredby {
color: #999;
color: rgba( 255, 255, 255, .25)
}
.sm {
width: 100%;
height: 2.5rem;
color: #444;
color: rgba( 0, 0, 0, .75);
background-color: #fff;
background-color: rgba( 255, 255, 255, .5);
overflow: hidden;
position: fixed;
z-index: 1001;
bottom: 0;
left: 0;
padding: .625rem 1.25rem 0
}
.sm--dark {
color: #ddd;
color: rgba( 255, 255, 255, .75);
background-color: #111;
background-color: rgba( 0, 0, 0, .5)
}
.sm ul {}
.sm li {
float: right;
margin-left: 1rem
}
.sm li:first-child {
float: left;
margin-left: 0
}
.sm .googleplus-one {
max-width: 60px
}
.sm .twitter-follow>*:not( :first-child),
.sm .twitter-share>*:not( :first-child) {
display: none
}
@media screen {
@media(min-width: 0px) {
.sm li:last-child {
opacity:0;
-webkit-transition: opacity .25s ease-in-out;
transition: opacity .25s ease-in-out
}
.sm:hover li:last-child {
opacity: 1
}
}
}
.sm__back {
font-size: .875rem;
font-weight: 700;
color: currentColor;
text-transform: uppercase;
position: relative
}
.sm__back::before {
width: 0;
height: 0;
border: .313rem solid transparent;
border-left: none;
border-right-color: currentColor;
content: '';
display: inline-block;
position: relative;
left: 0;
margin-right: .313rem;
-webkit-transition: left .25s ease-in-out;
transition: left .25s ease-in-out
}
.sm__back:hover::before,
.sm__back:focus::before {
left: -.313rem
}
@media screen and (max-width:40em),
screen and (max-height:40em) {
.ad,
.sm {
display: none
}
}
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<title>TEST</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="main.css" />
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,300italic,400" />
<style>
html {}
body {
font-family: Roboto, sans-serif;
color: #0f3c4b;
background-color: #e5edf1;
padding: 5rem 1.25rem;
/* 80 20 */
}
.container {
width: 100%;
max-width: 680px;
/* 800 */
text-align: center;
margin: 0 auto;
}
.container h1 {
font-size: 42px;
font-weight: 300;
color: #0f3c4b;
margin-bottom: 40px;
}
.container h1 a:hover,
.container h1 a:focus {
color: #39bfd3;
}
.container nav {
margin-bottom: 40px;
}
.container nav a {
border-bottom: 2px solid #c8dadf;
display: inline-block;
padding: 4px 8px;
margin: 0 5px;
}
.container nav a.is-selected {
font-weight: 700;
color: #39bfd3;
border-bottom-color: currentColor;
}
.container nav a:not( .is-selected):hover,
.container nav a:not( .is-selected):focus {
border-bottom-color: #0f3c4b;
}
.container footer {
color: #92b0b3;
margin-top: 40px;
}
.container footer p p {
margin-top: 1em;
}
.container footer a:hover,
.container footer a:focus {
color: #39bfd3;
}
.box {
font-size: 1.25rem;
/* 20 */
background-color: #c8dadf;
position: relative;
padding: 100px 20px;
}
.box.has-advanced-upload {
outline: 2px dashed #92b0b3;
outline-offset: -10px;
-webkit-transition: outline-offset .15s ease-in-out, background-color .15s linear;
transition: outline-offset .15s ease-in-out, background-color .15s linear;
}
.box.is-dragover {
outline-offset: -20px;
outline-color: #c8dadf;
background-color: #fff;
}
.box__dragndrop,
.box__icon {
display: none;
}
.box.has-advanced-upload .box__dragndrop {
display: inline;
}
.box.has-advanced-upload .box__icon {
width: 100%;
height: 80px;
fill: #92b0b3;
display: block;
margin-bottom: 40px;
}
.box.is-uploading .box__input,
.box.is-success .box__input,
.box.is-error .box__input {
visibility: hidden;
}
.box__uploading,
.box__success,
.box__error {
display: none;
}
.box.is-uploading .box__uploading,
.box.is-success .box__success,
.box.is-error .box__error {
display: block;
position: absolute;
top: 50%;
right: 0;
left: 0;
-webkit-transform: translateY( -50%);
transform: translateY( -50%);
}
.box__uploading {
font-style: italic;
}
.box__success {
-webkit-animation: appear-from-inside .25s ease-in-out;
animation: appear-from-inside .25s ease-in-out;
}
@-webkit-keyframes appear-from-inside {
from {
-webkit-transform: translateY( -50%) scale( 0);
}
75% {
-webkit-transform: translateY( -50%) scale( 1.1);
}
to {
-webkit-transform: translateY( -50%) scale( 1);
}
}
@keyframes appear-from-inside {
from {
transform: translateY( -50%) scale( 0);
}
75% {
transform: translateY( -50%) scale( 1.1);
}
to {
transform: translateY( -50%) scale( 1);
}
}
.box__restart {
font-weight: 700;
}
.box__restart:focus,
.box__restart:hover {
color: #39bfd3;
}
.js .box__file {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.js .box__file label {
max-width: 80%;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
display: inline-block;
overflow: hidden;
}
.js .box__file label:hover strong,
.box__file:focus label strong,
.box__file.has-focus label strong {
color: #39bfd3;
}
.js .box__file:focus label,
.js .box__file.has-focus label {
outline: 1px dotted #000;
outline: -webkit-focus-ring-color auto 5px;
}
.js .box__file label * {
/* pointer-events: none; */
/* in case of FastClick lib use */
}
.no-js .box__file label {
display: none;
}
.no-js .box__button {
display: block;
}
.box__button {
font-weight: 700;
color: #e5edf1;
background-color: #39bfd3;
display: block;
padding: 8px 16px;
margin: 40px auto 0;
}
.box__button:hover,
.box__button:focus {
background-color: #0f3c4b;
}
</style>
</head>
<body>
<div class="container" role="main">
<form action="https://s3-[removed].amazonaws.com/[removed]" method="post" enctype="multipart/form-data" novalidate class="box">
<input type="hidden" name="key" value="uploads/${filename}">
<input Access Key ID type="hidden" type="input" name="AWSAccessKeyId" value="[removed]">
<input Signature type="hidden" type="password" name="signature" value="[removed]">
<input type="hidden" name="acl" value="private">
<input type="hidden" name="success_action_redirect" value="[removed]">
<input type="hidden" name="x-amz-server-side-encryption" value="AES256" />
<input type="hidden" name="policy" value="[removed]" <!-- Include any additional input fields here -->
<input type="input" class="text-input" name="x-amz-meta-tag" value="" placeholder="Your Name Here" />
<div class="box__input">
<input type="file" name="file" id="file" class="box__file" data-multiple-caption="{count} files selected" multiple />
<label for="file"><strong>Choose a file</strong><span class="box__dragndrop"> or drag it here</span>.</label>
<button type="submit" class="box__button">Upload</button>
</div>
<div class="box__uploading">Uploadingamp;hellip;</div>
</form>
</div>
<script type="8f8d05b8d77097cd667d97f3-text/javascript">
'use strict';
;
(function(document, window, index) {
// feature detection for dragamp;drop upload
var isAdvancedUpload = function() {
var div = document.createElement('div');
return (('draggable' in div) || ('ondragstart' in div amp;amp; 'ondrop' in div)) amp;amp; 'FormData' in window amp;amp; 'FileReader' in window;
}();
// applying the effect for every form
var forms = document.querySelectorAll('.box');
Array.prototype.forEach.call(forms, function(form) {
var input = form.querySelector('input[type="file"]'),
label = form.querySelector('label'),
errorMsg = form.querySelector('.box__error span'),
restart = form.querySelectorAll('.box__restart'),
droppedFiles = false,
showFiles = function(files) {
label.textContent = files.length > 1 ? (input.getAttribute('data-multiple-caption') || '').replace('{count}', files.length) : files[0].name;
},
triggerFormSubmit = function() {
var event = document.createEvent('HTMLEvents');
event.initEvent('submit', true, false);
form.dispatchEvent(event);
};
// letting the server side to know we are going to make an Ajax request
var ajaxFlag = document.createElement('input');
ajaxFlag.setAttribute('type', 'hidden');
ajaxFlag.setAttribute('name', 'ajax');
ajaxFlag.setAttribute('value', 1);
form.appendChild(ajaxFlag);
// automatically submit the form on file select
input.addEventListener('change', function(e) {
showFiles(e.target.files);
});
// dragamp;drop files if the feature is available
if (isAdvancedUpload) {
form.classList.add('has-advanced-upload'); // letting the CSS part to know dragamp;drop is supported by the browser
['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach(function(event) {
form.addEventListener(event, function(e) {
// preventing the unwanted behaviours
e.preventDefault();
e.stopPropagation();
});
});
['dragover', 'dragenter'].forEach(function(event) {
form.addEventListener(event, function() {
form.classList.add('is-dragover');
});
});
['dragleave', 'dragend', 'drop'].forEach(function(event) {
form.addEventListener(event, function() {
form.classList.remove('is-dragover');
});
});
form.addEventListener('drop', function(e) {
droppedFiles = e.dataTransfer.files; // the files that were dropped
showFiles(droppedFiles);
});
}
// if the form was submitted
form.addEventListener('submit', function(e) {
// preventing the duplicate submissions if the current one is in progress
if (form.classList.contains('is-uploading')) return false;
form.classList.add('is-uploading');
form.classList.remove('is-error');
if (isAdvancedUpload) // ajax file upload for modern browsers
{
e.preventDefault();
// gathering the form data
var ajaxData = new FormData(form);
if (droppedFiles) {
Array.prototype.forEach.call(droppedFiles, function(file) {
ajaxData.append(input.getAttribute('name'), file);
});
}
// ajax request
var ajax = new XMLHttpRequest();
ajax.open(form.getAttribute('method'), form.getAttribute('action'), true);
ajax.onload = function() {
form.classList.remove('is-uploading');
if (ajax.status >= 200 amp;amp; ajax.status < 400) {
var data = JSON.parse(ajax.responseText);
form.classList.add(data.success == true ? 'is-success' : 'is-error');
if (!data.success) errorMsg.textContent = data.error;
} else alert(ajax.response);
};
ajax.onerror = function() {
form.classList.remove('is-uploading');
};
ajax.send(ajaxData);
} else // fallback Ajax solution upload for older browsers
{
var iframeName = 'uploadiframe' new Date().getTime(),
iframe = document.createElement('iframe');
$iframe = $('<iframe name="' iframeName '" style="display: none;"></iframe>');
iframe.setAttribute('name', iframeName);
iframe.style.display = 'none';
document.body.appendChild(iframe);
form.setAttribute('target', iframeName);
iframe.addEventListener('load', function() {
var data = JSON.parse(iframe.contentDocument.body.innerHTML);
form.classList.remove('is-uploading')
form.classList.add(data.success == true ? 'is-success' : 'is-error')
form.removeAttribute('target');
if (!data.success) errorMsg.textContent = data.error;
iframe.parentNode.removeChild(iframe);
});
}
});
// restart the form if has a state of error/success
Array.prototype.forEach.call(restart, function(entry) {
entry.addEventListener('click', function(e) {
e.preventDefault();
form.classList.remove('is-error', 'is-success');
input.click();
});
});
// Firefox focus bug fix for file input
input.addEventListener('focus', function() {
input.classList.add('has-focus');
});
input.addEventListener('blur', function() {
input.classList.remove('has-focus');
});
});
}(document, window, 0));
</script>
<script src="https://ajax.cloudflare.com/cdn-cgi/scripts/7089c43e/cloudflare-static/rocket-loader.min.js" data-cf-settings="8f8d05b8d77097cd667d97f3-|49" defer=""></script>
</body>
<div class="background"></div>
</html>
Комментарии:
1. Да, вам либо нужно создать несколько форм (что вы можете сделать, программно создав эти формы), либо
PUT
вместо этого использовать запрос.2. @Brad Возможно, я просто не знаю, что я делаю, но, похоже, я не могу заставить его отправить как PUT