小编典典

发送包含Safari 10.13.4中的空文件的FormData()时,AJAX请求失败

ajax

我正在运行一个基于Symfony 2.8的Web应用程序,该应用程序使用Ajax将一些表单数据发送回控制器。

到目前为止,一切工作正常,但是由于最新的macOS更新至版本10.13.4,用户开始报告,因此提交表单在Safari中不再起作用。10.13.4上的其他macOS版本和其他浏览器仍然可以正常工作,因此在Safari中似乎是一个问题。我当然向苹果提交了错误报告,但我认为我永远不会从那里得到反馈…

我能够找出问题的根源:提交包含空文件输入的数据失败:

// safri_bug.html
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    </head>
<body>
    <form name="app_booking" method="post" action="/test/submit.php">
        <div><input type="text" id="someValue" name="value"></div>
        <div><input id="thefile" type="file" name="file"></div>
    </form>

    <button id="bSubmit" type="button">Submit</button>

    <script>    
        $(document).ready(function() {              
            $('#bSubmit').click(function() {
                var form = $('form');
                var data = new FormData(form[0]);

                $.ajax({
                    url : '/submit.php',
                    type : 'POST',
                    data : data,
                    contentType: false,
                    processData: false,
                    context : this,
                    success : function(response) {
                            alert('success: ' + response);
                    },
                    error: function (xhr, ajaxOptions, thrownError) {
                            alert('error: ' + xhr.responseText + ' - ' + thrownError);
                    }
                });
            });
        });
    </script>
</body>
</html>


// submit.php
<?php 
    echo "OK";

结果

  • 在所有经过测试的浏览器和平台上,但在macOS 10.13.4的Safari中,提交表单都可以正常工作
  • 在macOS 10.13.4上的Safari中:
    • 如果未选择文件:Ajax请求将运行大约20秒钟(是否建立超时?),然后返回带有空的成功响应。该submit.php不会 被调用。
    • 如果选择了文件:一切正常…

因此,这似乎是最新的Safari更新中的错误? 还是我的代码有什么问题?

知道如何防止此错误吗?


阅读 259

收藏
2020-07-26

共1个答案

小编典典

同时,我找到了这种快速而肮脏的解决方案。但是实际上我正在寻找一个真正的解决方法。有任何想法吗?

// Filter out empty file just before the Ajax request
// Use try/catch since Safari < 10.13.4 does not support FormData.entries()
try {
   for (var pair of data.entries()) {
      if (pair[1] instanceof File && pair[1].name == '' && pair[1].size == 0)
         data.delete(pair[0]);  
   }
} catch(e) {}
2020-07-26