You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

移动端表单提交异常排查:iOS未使用上传字段时表单卡顿问题

解决iOS设备上未上传文件时表单提交卡住的问题

你遇到的是iOS Safari特有的FormData处理bug——当表单包含未选择文件的<input type="file">字段时,构造的FormData会导致AJAX请求异常超时,最终表现为提交按钮一直显示"Sending ..."且页面无响应。下面给出两种可靠的解决方案,以及优化建议:

方案一:临时移除空文件输入(简单直接)

在生成FormData之前,先把表单中没有选择文件的文件输入临时移除,提交完成后再恢复它们,这样就能绕过iOS的bug:

$('#reused_form').submit(function(e) {
    e.preventDefault();
    $form = $(this);

    // 1. 临时移除未选择文件的<input type="file">
    const emptyFileInputs = $form.find('input[type="file"]').filter(function() {
        return this.files.length === 0;
    }).detach();

    // 2. 更新按钮状态
    $('button[type="submit"]', $form).each(function() {
        const $btn = $(this);
        $btn.prop('type','button');
        $btn.prop('orig_label', $btn.text());
        $btn.text('Sending ...');
    });

    // 3. 构造FormData(此时已排除空文件输入)
    const formdata = new FormData(this);

    // 4. 把临时移除的输入元素加回表单
    emptyFileInputs.appendTo($form);

    // 5. 发送AJAX请求,新增超时和错误处理
    $.ajax({
        type: "POST",
        url: 'handler.php',
        data: formdata,
        success: after_form_submitted,
        dataType: 'json',
        processData: false,
        contentType: false,
        cache: false,
        timeout: 10000, // 设置10秒超时
        error: function(xhr, status, error) {
            // 出错时恢复按钮状态
            $('button[type="button"]', $form).each(function() {
                const $btn = $(this);
                const label = $btn.prop('orig_label');
                if (label) {
                    $btn.prop('type','submit');
                    $btn.text(label);
                    $btn.prop('orig_label','');
                }
            });
            // 给用户友好提示
            $('#error_message').html('<ul><li>提交超时或失败,请重试</li></ul>').show();
            $('#success_message').hide();
        }
    });
});

方案二:手动构建FormData(更灵活)

如果不想操作DOM元素,可以手动遍历表单字段,只把有值的字段(包括已选择的文件)加入FormData:

$('#reused_form').submit(function(e) {
    e.preventDefault();
    $form = $(this);

    // 更新按钮状态
    $('button[type="submit"]', $form).each(function() {
        const $btn = $(this);
        $btn.prop('type','button');
        $btn.prop('orig_label', $btn.text());
        $btn.text('Sending ...');
    });

    // 手动构造FormData
    const formdata = new FormData();

    // 添加非文件字段
    $form.find(':input:not([type="file"])').each(function() {
        // 排除按钮和禁用字段
        if (!$(this).is(':button, :disabled') && this.name) {
            formdata.append(this.name, $(this).val());
        }
    });

    // 添加已选择文件的字段(支持多文件上传)
    $form.find('input[type="file"]').each(function() {
        if (this.files.length > 0 && this.name) {
            for (let i = 0; i < this.files.length; i++) {
                formdata.append(this.name + '[]', this.files[i]);
            }
        }
    });

    // 发送AJAX请求(同样加上超时和错误处理)
    $.ajax({
        type: "POST",
        url: 'handler.php',
        data: formdata,
        success: after_form_submitted,
        dataType: 'json',
        processData: false,
        contentType: false,
        cache: false,
        timeout: 10000,
        error: function(xhr, status, error) {
            // 恢复按钮状态+提示用户
            $('button[type="button"]', $form).each(function() {
                const $btn = $(this);
                const label = $btn.prop('orig_label');
                if (label) {
                    $btn.prop('type','submit');
                    $btn.text(label);
                    $btn.prop('orig_label','');
                }
            });
            $('#error_message').html('<ul><li>提交超时或失败,请重试</li></ul>').show();
            $('#success_message').hide();
        }
    });
});

关键优化说明

  1. 超时处理:新增timeout参数,避免请求无限期挂起;
  2. 错误回调:在请求失败/超时时恢复按钮状态,同时给用户明确提示,提升体验;
  3. 字段过滤:两种方案都排除了空文件字段,从根源上避免iOS的FormData bug。

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

火山引擎 最新活动