Javascript FormData()文件上传到S3在Chrome中工作,但在Safari中不工作
在使用web应用程序时,我会将图像文件直接从浏览器发送到S3存储桶。这在Chrome中运行良好,但在Safari中没有错误,但代码最终将一个空文件上传到S3存储桶。一切基本上看起来都在Safari中工作,S3服务器甚至返回一个Javascript FormData()文件上传到S3在Chrome中工作,但在Safari中不工作,javascript,file-upload,amazon-s3,safari,Javascript,File Upload,Amazon S3,Safari,在使用web应用程序时,我会将图像文件直接从浏览器发送到S3存储桶。这在Chrome中运行良好,但在Safari中没有错误,但代码最终将一个空文件上传到S3存储桶。一切基本上看起来都在Safari中工作,S3服务器甚至返回一个204成功的http响应,文件看起来像在bucket中(但大小为0字节) 我正在调试,blobData在Chrome中的尺寸为55747,但在Safari中,对于同一图像,只有47560。另外,我在网络部分dev tools中发现了与此稍有不同的地方: 铬-工作(204响应
204
成功的http响应,文件看起来像在bucket中(但大小为0字节)
我正在调试,blobData
在Chrome中的尺寸为55747,但在Safari中,对于同一图像,只有47560。另外,我在网络部分dev tools中发现了与此稍有不同的地方:
铬-工作(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'});
}
我记得Safari对FormData对象的支持有限,例如:
我们可以调整图像文件的大小并上传到服务器。在Chrome和Safari上测试,两者都很好
fileChange() {
var fileInputTag = document.getElementById("myFile");
if ('files' in fileInputTag) {
if (fileInputTag.files.length > 0) {
var file = fileInputTag.files[0];
var type = 'image/jpeg',
maxWidth = 800,
maxHeight = 600,
quality = 0.5,
ratio = 1,
canvas = document.createElement('canvas'),
context = canvas['getContext']('2d'),
canvasCopy = document.createElement('canvas'),
copyContext = canvasCopy.getContext('2d'),
img = new Image();
img.onload = function () {
if (img.width > maxWidth) {
ratio = maxWidth / img.width;
} else if (img.height > maxHeight) {
ratio = maxHeight / img.height;
}
canvasCopy.width = img.width;
canvasCopy.height = img.height;
copyContext.drawImage(img, 0, 0);
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
context.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);
canvas.toBlob((blob) => {
blob['name'] = file.name.split('.')[0] + '.jpeg';
var formData:FormData = new FormData();
formData.append('uploadFile', blob, blob.name);
// do upload here
}, type, quality);
};
img.src = URL.createObjectURL(file);
}
}
}
将其添加到index.html或在执行上述脚本之前执行它
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function (callback, type, quality) {
var binStr = atob( this.toDataURL(type, quality).split(',')[1] ),
len = binStr.length,
arr = new Uint8Array(len);
for (var i = 0; i < len; i++ ) {
arr[i] = binStr.charCodeAt(i);
}
callback( new Blob( [arr], {type: type || 'image/png'} ) );
}
});
}
if(!htmlcanvaseelement.prototype.toBlob){
Object.defineProperty(htmlcanvaseElement.prototype,“toBlob”{
值:函数(回调、类型、质量){
var binStr=atob(this.toDataURL(type,quality).split(',')[1]),
len=binStr.长度,
arr=新的UINT8阵列(len);
对于(变量i=0;i
设置功能的大字“不支持”看起来不太好。谢谢,虽然我正在使用的append
方法有一个红色的?
。不确定,但是他们有这两个脚注:[1]在Gecko 7.0(Firefox 7.0/Thunderbird 7.0/SeaMonkey 2.4)之前,如果您指定一个Blob作为要附加到对象的数据,则在“内容配置”中报告的文件名HTTP头是一个空字符串;这导致某些服务器报告错误。从Gecko7.0开始,发送文件名“blob”。[2] Android 4.0中的XHR为带有blob的FormData发送空内容。我假设有些东西是部分兼容的?是的,我正在寻找解决办法,似乎它不完全安全,允许开发人员设置文件输入的值。broswer只允许用户选择文件…你解决了吗?我现在也有同样的问题,我已经被困了好几天了now@user2634633好。。。有点解决了。因此,它指出这是Safari navigator的一个重要安全功能。它不允许程序改变文件输入的内容。安全性背后的想法是,它只允许上传用户自己实际选择的文件。所以我的工作方法是在表单中使用一个普通的文件输入元素,然后从中上传。我决定在上传之前不调整图像大小,但在上传整个文件后在S3服务器上进行了处理。谢谢你提供的信息。最后,我在客户机上进行了裁剪和调整大小,并将数据URI发送到服务器,服务器将其转换为文件并进行S3上传。这有点迂回,但想不出更好的办法了。@user2634633这样,您仍然需要先将文件上传回服务器,对吗?但是我想如果你在客户端调整它的大小,你会在上传回服务器的过程中节省一点,但是你会失去从客户端直接上传到s3所节省的资源。我收回这一点——我刚刚设法让它与Safari的客户端上传一起工作。问题在于我的缩放代码,而不是上传代码。我同步设置了image.src
,这是一个异步操作,即使与特定的数据URI一起使用也是如此。在Chrome上,这不是问题,但在Safari上,图像高度和宽度设置为0,因为我没有等待图像加载,因此文件大小为0b。检查您的数据\u url
在Safari和Chrome上是否相同。在使用image.onload
回调使缩放函数异步后,一切都正常!
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function (callback, type, quality) {
var binStr = atob( this.toDataURL(type, quality).split(',')[1] ),
len = binStr.length,
arr = new Uint8Array(len);
for (var i = 0; i < len; i++ ) {
arr[i] = binStr.charCodeAt(i);
}
callback( new Blob( [arr], {type: type || 'image/png'} ) );
}
});
}