【发布时间】:2017-06-03 18:57:39
【问题描述】:
在开发 Web 应用程序时,我将图像文件从浏览器直接发送到 S3 存储桶。这在 Chrome 中运行良好,但在 Safari 中没有错误,但代码最终将一个空文件上传到 S3 存储桶。一切基本上看起来都在 Safari 中工作,S3 服务器甚至返回了一个 204 成功的 http 响应,并且文件看起来像是在存储桶中(但大小为 0 字节)。
我正在调试,blobData 在 Chrome 中的大小为 55747,但在 Safari 中对于同一图像只有 47560 的大小。另外,我发现在网络部分开发工具中看起来略有不同:
Chrome - 工作(204 响应的大小为正数 ~ 534B):
Safari - 不使用空文件(大小列仅显示虚线)
这里是JS上传代码:
function uploadFile(data_url, s3Data, url, filename, id, thumbnail_url){
var xhr = new XMLHttpRequest();
xhr.open("POST", s3Data.url);
var postData = new FormData();
for(key in s3Data.fields){
postData.append(key, s3Data.fields[key]);
}
var blobData = dataURItoBlob(data_url);
postData.append('file', new File([blobData], filename));
xhr.onreadystatechange = function() {
if(xhr.readyState === 4){
if(xhr.status === 200 || xhr.status === 204){
setTimeout(function(){
$('#photo_container').append('<div id="image_container_'+id+'" class="hover-card mdl-cell--3-col-desktop mdl-cell--2-col-tablet mdl-cell--2-col-phone mdl-shadow--2dp"></div>');
$('.star-image').unbind('click').click( star_image_click );
$('.close-image').unbind('click').click(remove_image_click);
loading_files -= 1;
if ( loading_files == 0 ) {
$('#photo_load_spinner').removeClass('is-active');
$('#photo_load_text').text("");
}else{
$('#photo_load_text').text(loading_files+" files loading. Please wait.");
}
}, 1000);
}else{
alert("Could not upload file. "+xhr.responseText);
}
}
};
xhr.send(postData);
}
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/png'});
}
我不知道接下来要寻找什么。任何帮助将不胜感激。谢谢!
编辑
只是想我应该提供更多信息。 data_url 是从我用来在浏览器中调整图像大小的画布元素生成的,尽管我已经确认画布在上传之前在 safari 中正确显示了图像。这是代码:
function ResizeFile(raw_file) {
var reader = new FileReader();
reader.onload = function(e) {
var img = document.createElement("img");
img.onload = function() {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
//ctx.drawImage(img, 0, 0);
var MAX = 1200;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX) {
height *= MAX / width;
width = MAX;
}
} else {
if (height > MAX) {
width *= MAX / height;
height = MAX;
}
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/png");
getSignedRequest(dataurl);
}
img.src = e.target.result;
}
reader.readAsDataURL(raw_file);
}
【问题讨论】:
-
你解决了吗?我现在遇到了同样的问题,我已经卡了好几天了
-
@user2634633 好吧......有点解决了。因此,它被认为是 Safari navigator 的一项重要安全功能。它不允许程序更改文件输入的内容。安全性背后的想法是,它只允许上传用户实际选择的文件。所以我解决的方法是在表单中使用普通的文件输入元素,然后从中上传。我决定在上传之前不进行图像调整大小,而是在上传整个文件后在 S3 服务器上进行处理。
-
感谢您的信息。我最终在客户端上裁剪和调整大小,并将数据 URI 发送到服务器,服务器将其转换为文件并进行 S3 上传。有点绕,但是想不出更好的了。
-
@user2634633 这样您仍然需要先将文件上传回您的服务器,对吧?但我想如果你在客户端调整它的大小,你会在上传回服务器时节省一点,但是你会失去从客户端直接上传到 s3 的资源节省。
-
我收回了这一点——我刚刚设法让它与从 Safari 上传的客户端一起工作。问题出在我的缩放代码中,而不是上传代码中。我同步设置
image.src,虽然它是一个异步操作,即使与特定数据URI一起使用也是如此。在 Chrome 上,这不是问题,但在 Safari 上,图像高度和宽度设置为 0,因为我没有等待图像加载 - 因此文件大小为 0b。检查您的data_url在 Safari 和 Chrome 上是否相同。通过使用image.onload回调使我的缩放功能异步后,一切正常!
标签: javascript file-upload amazon-s3 safari