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

Vue组件中如何缓存文件上传,避免ERR_UPLOAD_FILE_CHANGED错误?

解决Vue组件中「ERR_UPLOAD_FILE_CHANGED」的前端文件缓存方案

问题背景

开发的Vue组件支持CSV文件上传、预览处理结果,确认后执行系统变更,但浏览器偶尔抛出「ERR_UPLOAD_FILE_CHANGED」错误——这是因为用户在上传后到确认执行的间隙修改了原文件,浏览器检测到文件内容/元数据变化,阻止后续上传操作。

解决方案:前端缓存已上传文件

核心思路是在用户首次上传时,将文件内容完整读取并缓存到内存(或IndexedDB,针对大文件),后续确认执行时直接提交缓存的内容,而非依赖原文件对象。

方案1:内存缓存(适合小体积CSV文件)

利用FileReader读取文件内容,转为Blob后重新构造File对象缓存,彻底脱离对本地原文件的依赖。

<template>
  <div>
    <input type="file" accept=".csv" @change="handleFileUpload" />
    <button @click="previewResult">预览结果</button>
    <button @click="confirmChange" :disabled="!cachedFile">确认执行变更</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const cachedFile = ref(null) // 缓存处理后的File对象
const originalFileName = ref('')

const handleFileUpload = (e) => {
  const file = e.target.files[0]
  if (!file) return

  originalFileName.value = file.name
  const reader = new FileReader()

  reader.onload = (event) => {
    // 将读取到的内容转为Blob,再构造新的File对象
    const blob = new Blob([event.target.result], { type: file.type })
    cachedFile.value = new File([blob], originalFileName.value, {
      type: file.type,
      lastModified: Date.now() // 固定修改时间,避免浏览器检测到原文件变化
    })
  }

  reader.readAsArrayBuffer(file)
}

const previewResult = () => {
  if (!cachedFile.value) return
  // 这里用cachedFile.value做预览处理,比如解析CSV内容展示
  // ... 预览逻辑
}

const confirmChange = async () => {
  if (!cachedFile.value) return

  // 构造FormData提交缓存的文件
  const formData = new FormData()
  formData.append('csvFile', cachedFile.value)

  try {
    await fetch('/api/submit-change', {
      method: 'POST',
      body: formData
    })
    // 提交成功后清空缓存
    cachedFile.value = null
    originalFileName.value = ''
  } catch (err) {
    console.error('提交失败:', err)
  }
}
</script>

方案2:IndexedDB缓存(适合大体积CSV文件)

如果CSV文件体积较大(比如超过100MB),内存缓存可能导致性能问题,此时用IndexedDB持久化缓存文件内容,流程完成后再删除。

<template>
  <!-- 同方案1的模板结构 -->
</template>

<script setup>
import { ref } from 'vue'
import { openDB } from 'idb' // 先安装依赖:npm install idb

const cachedFileKey = 'uploaded-csv-file'
const originalFileName = ref('')
// 初始化IndexedDB实例
const dbPromise = openDB('FileCacheDB', 1, {
  upgrade(db) {
    db.createObjectStore('files')
  }
})

const handleFileUpload = async (e) => {
  const file = e.target.files[0]
  if (!file) return

  originalFileName.value = file.name
  const arrayBuffer = await file.arrayBuffer()
  
  // 将文件内容存入IndexedDB
  const db = await dbPromise
  await db.put('files', arrayBuffer, cachedFileKey)
}

const previewResult = async () => {
  const db = await dbPromise
  const arrayBuffer = await db.get('files', cachedFileKey)
  if (!arrayBuffer) return

  // 构造File对象用于预览解析
  const file = new File([arrayBuffer], originalFileName.value, { type: 'text/csv' })
  // ... 预览逻辑
}

const confirmChange = async () => {
  const db = await dbPromise
  const arrayBuffer = await db.get('files', cachedFileKey)
  if (!arrayBuffer) return

  // 构造File对象提交
  const file = new File([arrayBuffer], originalFileName.value, { type: 'text/csv' })
  const formData = new FormData()
  formData.append('csvFile', file)

  try {
    await fetch('/api/submit-change', {
      method: 'POST',
      body: formData
    })
    // 提交成功后删除缓存
    await db.delete('files', cachedFileKey)
    originalFileName.value = ''
  } catch (err) {
    console.error('提交失败:', err)
  }
}
</script>

关键注意点

  • 彻底脱离原File对象:原File对象关联本地文件,一旦文件被修改就会触发错误,必须用缓存内容重新构造独立的File对象。
  • 及时清理缓存:流程完成(成功/失败)后务必清空缓存,避免占用内存或存储资源。
  • 文件校验:上传时严格校验文件类型为.csv,避免无效文件进入缓存流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 01:44:51