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

如何通过JS File Upload API终止Laravel Livewire中的文件上传?

解决Laravel Livewire文件上传的取消问题

针对你的大文件上传取消需求,目前Livewire官方确实没有提供原生的取消API,但可以通过拦截并保存上传的XHR实例来实现,具体步骤如下:

1. 捕获上传的XHR实例

在页面的JavaScript中,重写Livewire的startUpload方法,保存每次上传的XHR对象,后续就能调用abort()方法取消上传:

// 存储当前活跃的上传XHR(单文件用变量,多文件用对象/数组)
let activeUploadXHR = null;

// 备份原上传方法
const originalStartUpload = Livewire.startUpload;

// 重写上传方法,捕获XHR
Livewire.startUpload = function(uploaderId, file, options) {
    // 调用原方法并获取返回的XHR实例
    activeUploadXHR = originalStartUpload.call(this, uploaderId, file, options);
    // 上传完成/失败后清空实例
    activeUploadXHR.addEventListener('loadend', () => activeUploadXHR = null);
    return activeUploadXHR;
};

// 取消上传的函数
function cancelCurrentUpload() {
    if (activeUploadXHR && activeUploadXHR.readyState !== 4) {
        // 终止XHR请求
        activeUploadXHR.abort();
        // 通知Livewire组件处理取消后的状态
        Livewire.emit('uploadCancelled');
        activeUploadXHR = null;
    }
}

2. 组件内处理取消事件

在你的Livewire组件中,监听前端发来的uploadCancelled事件,清理临时文件或更新组件状态:

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\WithFileUploads;
use Illuminate\Support\Facades\Storage;

class FileUploader extends Component
{
    use WithFileUploads;

    public $temporaryFile;

    protected $listeners = ['uploadCancelled' => 'handleUploadCancellation'];

    public function handleUploadCancellation()
    {
        // 清理临时上传的文件
        if ($this->temporaryFile) {
            Storage::delete($this->temporaryFile->getRealPath());
            $this->temporaryFile = null;
        }
        // 添加取消提示
        $this->addError('upload', '上传已取消');
    }

    // 你的文件上传逻辑
    public function saveFile()
    {
        try {
            $this->validate([
                'temporaryFile' => 'file|max:1024000', // 1GB限制
            ]);

            // 处理文件存储逻辑
            // $this->temporaryFile->store('uploads');
        } catch (\Exception $e) {
            // 捕获XHR终止导致的异常,避免错误提示混乱
            if (str_contains($e->getMessage(), 'abort') || str_contains($e->getMessage(), 'Client abort')) {
                return;
            }
            $this->addError('upload', '上传失败:' . $e->getMessage());
        }
    }

    public function render()
    {
        return view('livewire.file-uploader');
    }
}

3. 添加UI取消按钮

在Blade视图中,添加取消按钮,仅在上传中显示:

<div>
    <input type="file" wire:model="temporaryFile">

    @error('upload')
        <div class="text-red-500 mt-2">{{ $message }}</div>
    @enderror

    <button wire:click="saveFile" wire:loading.attr="disabled" class="mt-2 btn btn-primary">
        开始上传
    </button>

    <!-- 取消按钮:上传中显示 -->
    <button onclick="cancelCurrentUpload()" wire:loading class="mt-2 ml-2 btn btn-danger">
        取消上传
    </button>

    <div wire:loading>上传中...</div>
</div>

多文件上传的适配

如果是多文件上传,需要用对象存储每个文件的XHR实例,以文件的唯一标识(如name+size)作为键:

let activeUploads = {};

const originalStartUpload = Livewire.startUpload;
Livewire.startUpload = function(uploaderId, file, options) {
    const xhr = originalStartUpload.call(this, uploaderId, file, options);
    const fileKey = `${file.name}-${file.size}`;
    activeUploads[fileKey] = xhr;
    
    xhr.addEventListener('loadend', () => delete activeUploads[fileKey]);
    return xhr;
};

function cancelUpload(fileKey) {
    const xhr = activeUploads[fileKey];
    if (xhr && xhr.readyState !== 4) {
        xhr.abort();
        Livewire.emit('uploadCancelled', fileKey);
        delete activeUploads[fileKey];
    }
}

组件内则根据fileKey对应处理单个文件的取消逻辑即可。

注意事项

  • 该方法依赖Livewire的内部startUpload方法返回XHR实例,当前v2/v3版本均适用,若后续Livewire更新该方法实现,可能需要调整代码。
  • 取消上传后,服务器端可能仍会收到部分文件数据,需要确保临时文件清理逻辑能正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 00:40:11