龙空技术网

前后端开发文件上传

青少年编程ABC 221

前言:

此时各位老铁们对“ie formdata 未定义”大体比较关怀,咱们都想要剖析一些“ie formdata 未定义”的相关内容。那么小编同时在网摘上收集了一些关于“ie formdata 未定义””的相关资讯,希望兄弟们能喜欢,大家一起来了解一下吧!

文件上传1.环境

前端

Vue3

PrimeVUE

后端

Python

FastAPI

2.文件存储

在软件开发中,上传文件是经常会使用到的一个功能,那么文件存储也就变得非常重要起来了。在以往的小项目中,文件存储都是在直接在磁盘上存储的,但这样的方式,随着微服务的发展,部署在不同机器上的微服务之间需要共享数据,直接存储在磁盘上的文件就不方便文件共享了。鉴于此,我们在开发相对较大的软件时,就需要将文件存储在数据库或者分布式文件系统中,在此,我们选择了MongoDB的GridFS来存储文件,也就是说在文件上传时将文件存储到MongoDB数据库中,然后接口返回文件的OID。

3.文件上传方式

文件上传一般的方式是需要支持单文件上传和多文件上传的,但本质上来讲是一回事,所以在设计文件上传接口时,我们将文件上传统一为一个接口,支持多个文件上传即可。

4.后端文件上传源代码

# coding: utf-8import settingsfrom logger import loggerfrom api.upload import routerfrom fastapi import Filefrom fastapi import Dependsfrom fastapi import UploadFilefrom typing import Listfrom pymongo import MongoClientfrom gridfs import GridFSfrom common.common import find_current_usr@router.post(path='/upload_files')async def upload_files(files: List[UploadFile] = File(...), current_usr: dict = Depends(find_current_usr)):    res = {'res': False, 'oids': []}    with MongoClient(settings.MONGO_HOST, settings.MONGO_PORT) as connect:        filedb = connect.filedb        mgfs = GridFS(filedb)        for file in files:            # 写入gridfs            logger.log('Upload file {0} from {1}'.format(file.filename, current_usr['name']))            dic = dict()            dic['filename'] = file.filename            oid = mgfs.put(await file.read(), **dic)            res['oids'].append(str(oid))        res['res'] = True    return res

通过以上源代码,我们可以看到:接口接收在表单中传递的 files 参数,files 类型为列表,然后对接收到的文件循环写入 MongoDB,最后返回 MongoDB 的文件 OID 列表。返回值:

{'res': False, 'oids': []}

其中:res 表示是否上传成功,oids 表示 MongoDB 文件 OID 列表。

5.前端文件上传封装

由于后端接收的是文件,而不是普通的数据,所以前端在传输数据时必须以表单的形式传递,也就是说,请求头中必须指定:

'Content-Type': 'multipart/form-data'

另外由于在上传文件时需要携带令牌,所以,需要对上传文件的 js 代码进行封装,代码如下:

function errorToString (error) {  let text = ''  if (error.response.data) {    if (error.response.data instanceof Object)      text = JSON.stringify(error.response.data)    else      text = error.response.data  }  return text}// 文件上传const fileConfig = {  baseURL: '',  timeout: 60000,  headers: {    'Content-Type': 'multipart/form-data'  },  responseType: 'json'}// 携带令牌的文件上传const uploadRequest = (url, data) => {  let _id = loading()  // eslint-disable-next-line  const promise = new Promise((resolve, reject) => {    fileConfig.headers['Authorization'] =        localStorage.getItem('token_type') + ' ' + localStorage.getItem('access_token')    axios.post(        url, data, fileConfig    ).then((response) => {      loaded(_id)      resolve(response)    }).catch((error) => {      loaded(_id)      console.log(error)      // 对error中的数据进行处理      let status = error.response.status      let txt = errorToString(error)      // 弹出错误信息      if (status === 401) {        swal({          title: status.toString(),          text: txt,          icon: 'error',          button: "确定",        }).then((value) => {          console.log(value)          window.top.location.href = '/index.html'        })      } else {        swal(status.toString(), txt, 'error')      }      // reject(error)    })  })  return promise}

这样经过封装后,前端在上传文件时,只需要调用 uploadRequest 函数就可以完成文件的上传,调用格式:

      uploadRequest(          '/qycommon_api/upload/upload_files',          formData      ).then((response) => {        if (response.data.res) {          ......        } else {          ......        }      })

在上面的代码中,我们看到 formData 这个变量,那么下面我们来说明一下前端上传文件的方法。

6.前端上传文件代码

前端上传文件,我们采用 PrimeVUE 的 upload 组件,该组件实际上是一个三态组件,包括:选择文件、上传文件、取消文件。但我们在一般的使用中,希望做到直接选择文件后就上传,同时获取到上传文件的 OID ,然后将 OID 记录到数据表中。实现代码如下:

组件

            <FileUpload                  name="demo[]"                  mode="basic"                  accept="image/*"                  chooseLabel="更换"                  :auto="true"                  @select="upload_avatar_file"/>

事件

  upload_avatar_file (event) {      var formData = new FormData()      event.files.forEach((file) => {        formData.append('files', file)      })      let _this = this      uploadRequest(          '/qycommon_api/upload/upload_files',          formData      ).then((response) => {        if (response.data.res) {          swal({title: "提示!", text: "操作成功!", icon: "success", button: false, timer: 1000})          _this.download_avatar_file(response.data.oids[0])  // 下载文件          _this.write_my_avatar(response.data.oids[0])  // 将文件的 OID 写入数据表        } else {          swal({title: "提示!", text: "操作失败!", icon: "error", button: false, timer: 1000})        }      })    },

说明:

1.select 事件

在组件中,我们使用了 select 事件来上传文件,而不是 uploader 事件,同时将 auto 设置为 true,表示使用自动上传。这样会在上传文件时出现错误,因为我们没有指定组件的 url ,但不会有问题,因为我们在选择文件时已经将文件上传了。只是在浏览器的调试环境中可以看到请求了一个 null 的错误。

2.FormData

在自定义的文件上传中,我们使用了 FormData ,循环将文件写入 FormData 的 files 中。

标签: #ie formdata 未定义 #前端传文件给后端用什么格式