2017-01-19 11 views
3

ウェブアプリケーションで作業していますが、画像ファイルはブラウザからS3バケットに直接送られています。これはChromeでもうまくいきますが、Safariではエラーはありませんが、コードは空のファイルをS3バケットにアップロードしてしまいます。基本的にSafariで動作するようなものはすべて、S3サーバーは204成功したHTTP応答を返すだけで、ファイルはバケツのようです(サイズは0バイトです)。Javascript FormData()S3へのファイルアップロードはChromeで動作しますが、Safariでは動作しません

私はデバッグしています。blobDataのサイズはChromeで55747でしたが、同じ画像でSafariでは47560サイズでした。また、私は少し違って見えるものを発見したネットワーキング・セクションのdevのツールである:

クロム - ワーキング(204応答は〜正のサイズを持ってい534B):

enter image description here

サファリ - 空のファイルで作業していません

:ここでJSのアップロードのコードがある

enter image description here

(サイズの欄には、ちょうどダッシュラインを示して)

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'}); 
    } 

私は次に何を探すべきかについて迷っています。どんな助けでも大歓迎です。ありがとう!

EDIT

だけの図は、私は少しより多くの情報を与えるべきです。 data_urlは、ブラウザで画像のサイズを変更するキャンバス要素から生成されますが、アップロード前にキャンバスが画像をサファリに正しく表示することが確認されています。ここではそのコードは次のとおりです。

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); 
    } 
+0

あなたはそれを解決するために管理しました上記のスクリプトの実行前にそれを実行しますか?私は現時点で同じ問題を抱えている、私は今日中それに固執してきた – user2634633

+0

@ user2634633まあ...ちょっとそれを解決しました。だから、それはSafariナビゲータの重要なセキュリティ機能だと言います。プログラムがファイル入力の内容を変更することを許可していません。セキュリティの背後にあるアイデアは、ユーザーが実際に自分自身を選んだファイルのアップロードのみを許可するということです。ですから、私が取り組んだのは、通常のファイル入力要素をフォームに使用し、そこからアップロードすることでした。アップロード前に画像のサイズを変更しないことにしましたが、ファイル全体をアップロードした後でS3サーバーでその処理を行いました。情報のおかげで –

+0

ありがとうございます。私は、クライアント上でトリミングとサイズ変更を行い、サーバーにデータURIを送信しました。サーバーはファイルをS3にアップロードしてアップロードします。それは少し迂回していますが、それ以上のことは考えられません。 – user2634633

答えて

1

私はSafariが、たとえば、いるFormDataオブジェクトを限定的にサポートした覚え:

https://developer.mozilla.org/en-US/docs/Web/API/FormData/set

https://developer.mozilla.org/en-US/docs/Web/API/FormData/get

+0

'set'関数の大きなサポートはサポートされていません。ありがとう、私が使用している 'append'メソッドの赤い'? 'があります。 –

+1

確かにわかりませんが、そこに2つの脚注があります: [1] Gecko 7.0(Firefox 7.0/Thunderbird 7.0/SeaMonkey 2.4)より前に、オブジェクトに追加するデータとしてBlobを指定した場合、 "Content-Disposition" HTTPヘッダーは空の文字列でした。その結果、一部のサーバーによってエラーが報告されました。 Gecko 7.0以降、ファイル名 "blob"が送信されます。 [2] Android 4.0のXHRは、FormDataの空のコンテンツをblobで送信します。 私は部分的に準拠していると思われますか? – MahdeTo

+0

ええ私は回避策を検討しており、開発者がファイル入力の値を設定できるように完全に安全ではないようです。 broswerは、ユーザーがファイルを選択できるようになっているだけです... –

3

我々は、画像ファイルのサイズを変更して、サーバーにアップロードすることができます。 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'})); 
    } 
    }); 
} 
関連する問題