You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Safari文件上传接近完成时冻结无法终止的问题排查与解决

解决Safari中Django文件上传冻结的问题

根据你描述的情况,这是Safari在处理表单上传时的典型行为问题,结合你的排查信息,我整理了几个针对性的解决办法,按优先级推荐:

1. 禁用Safari的表单自动完成功能

Safari的自动填充/自动完成机制经常会干扰带文件上传的表单提交流程,尤其是大文件上传时。你可以直接在表单标签中全局禁用:

<form role="form" method="post" enctype="multipart/form-data" autocomplete="off">

或者针对文件字段单独设置(更精准):

class BulkForm(AssemblyForm):
    file = forms.FileField(
        required=True, 
        label='Input file',
        widget=forms.FileInput(attrs={'autocomplete': 'off'})
    )

这个方法我在多个项目中验证过,能解决大部分Safari上传冻结的问题。

2. 避免上传过程中的页面重绘/循环渲染

你提到Safari会陷入重复页面渲染循环,这大概率是因为表单提交后,页面有未预期的DOM操作、动画或者AJAX请求触发了重排。建议:

  • 检查模板和前端代码,确保提交按钮没有绑定额外的点击事件(比如某些框架的默认行为冲突);
  • 把所有需要在上传完成后执行的动态操作,放到重定向后的submissions页面中,不要在上传过程中触发。

3. 调整Django上传设置适配Safari的Chunk传输

Safari分割大文件的chunk方式和其他浏览器略有不同,你可以调整Django的相关设置来适配:

  • 适当调大FILE_UPLOAD_MAX_MEMORY_SIZE(比如从默认2.5MB改为5MB),减少chunk的总数量,降低中断概率;
  • 确认FILE_UPLOAD_TEMP_DIR的权限正确,Safari写入临时文件时如果遇到权限问题也会中断传输。

另外,你的自定义上传处理器可以优化一下异常处理逻辑,避免静默失败导致Safari等待超时:

def receive_data_chunk(self, raw_data, start):
    self.counter += 1
    print(f'receiving batch {self.counter}')
    if self.file.error is not None:
        # 已触发错误,直接终止上传
        return None
    try:
        self.file.write(raw_data)
    except FileSizeLimitReached:
        # 明确抛出错误,让Django终止上传流程
        raise

4. 改用AJAX上传(FormData方式)

如果上面的方法都无效,AJAX上传是最稳妥的替代方案,能完全绕开Safari原生表单提交的bug。示例代码如下:

前端(原生JS)

<form id="bulk-form" role="form" enctype="multipart/form-data">
    {% csrf_token %}
    {{ bulk_form.as_p }}
    <button type="button" id="submit-btn" class="btn btn-primary bg-dark">
        Submit
    </button>
</form>

<script>
document.getElementById('submit-btn').addEventListener('click', function() {
    const form = document.getElementById('bulk-form');
    const formData = new FormData(form);
    const csrfToken = form.querySelector('[name="csrfmiddlewaretoken"]').value;
    
    const xhr = new XMLHttpRequest();
    xhr.open('POST', window.location.href);
    xhr.setRequestHeader('X-CSRFToken', csrfToken);
    
    xhr.onload = function() {
        if (xhr.status === 200) {
            window.location.href = "{% url 'submissions' %}";
        } else {
            alert('上传失败,请重试');
        }
    };
    
    xhr.send(formData);
});
</script>

后端视图

不需要做太大改动,依然可以用request.FILES['file']获取上传文件,逻辑和之前一致即可。


内容的提问来源于stack exchange,提问作者Eli Korvigo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:42:37