#概要
Ajax経由でファイルをUploadしている部分が、MacのSafariブラウザでだけうまくUploadできない現象があった。
safariのバージョンは2019年8月現在の最新版で、確認に使ったバージョンは12.1.1でした。
#結論
SafariでForm要素をclone()で複製した際に、Safariではファイルオブジェクトは空要素としてCloneされるため、挙動が異なります。その結果Safariではファイル要素がアップロードされているようでいて、中身が空になってしまいます。
#詳細
不具合が起きたソースの概略は下記の通り。フォームでファイルを選択すると、Submitボタンを押すことなく、Ajaxで送信し、プレビューに表示するような動作となっています。アップロード中を示す動作や、サーバからのエラー処理などは省いています。
###HTML部分
<img src="/imgages/default.png" id="preview" alt="アップロード画像">
<form action="/fileupload.php" id="fileupload">
<input type="file" name="upload" id="upload">
</form>
JS部分
$('#upload').on('change', function(e){
e.preventDefault();
// 下記の部分でコピーされるデータがSafariと他のブラウザで異なります。
let cloneFormData = $('#fileupload').clone();
let fd = new FormData(cloneFormData.get(0));
let url = '/uploader.php';
$.ajax({
url: url,
type: 'post',
contentType: false,
processData: false,
cache: false,
data: fd
}).done(function (e) {
$('#preview').attr('src', e.file.uploaded_url); // プレビュー用の画像を表示
});
});
jQueryオブジェクトをcloneしている箇所は下記の部分です。
let cloneFormData = $('#form_input_file').clone();
「ネットワーク」タブから送信しているPOSTデータを見てみると、clone()をした場合、下記のようにfilename が取れていません。
clone()しないで、フォームオブジェクトを直接POSTした場合は下記のようにfilenameが取れています。
(データ本体はSafariでは見えないようで)
あとは、HTMLプロトコルのヘッダ部分Content-lengthを見ても、何らか大きめのデータをアップしていることが確認できます。
ちなみにデバッガで送信するフォームデータを見るとcloneしなかった場合でもした場合でも、下記のように見えるので中身がよくわかりません。
ということで、Safariで ファイルオブジェクトがあるform を clone した場合、
ファイルオブジェクトは空要素としてCloneされるようです。