网站首页 > 技术文章 正文
文件上传
1.环境
前端 | Vue3 |
PrimeVUE | |
后端 | Python |
FastAPI |
2.文件存储
在软件开发中,上传文件是经常会使用到的一个功能,那么文件存储也就变得非常重要起来了。在以往的小项目中,文件存储都是在直接在磁盘上存储的,但这样的方式,随着微服务的发展,部署在不同机器上的微服务之间需要共享数据,直接存储在磁盘上的文件就不方便文件共享了。鉴于此,我们在开发相对较大的软件时,就需要将文件存储在数据库或者分布式文件系统中,在此,我们选择了MongoDB的GridFS来存储文件,也就是说在文件上传时将文件存储到MongoDB数据库中,然后接口返回文件的OID。
3.文件上传方式
文件上传一般的方式是需要支持单文件上传和多文件上传的,但本质上来讲是一回事,所以在设计文件上传接口时,我们将文件上传统一为一个接口,支持多个文件上传即可。
4.后端文件上传源代码
# coding: utf-8
import settings
from logger import logger
from api.upload import router
from fastapi import File
from fastapi import Depends
from fastapi import UploadFile
from typing import List
from pymongo import MongoClient
from gridfs import GridFS
from 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 中。
猜你喜欢
- 2025-06-15 Nodejs文件上传、监听上传进度(node监听文件变化)
- 2025-06-15 Express 文件上传不迷路:req.files 一次性讲明白
- 2025-06-15 JAVA大文件上传,大文件下载解决方案
- 2025-06-15 深入掌握 OSS:最完美的 OSS 上传方案!
- 2025-06-15 AspNetCore中的文件上传与下载优化
- 2025-06-15 【前后台完整版】大文件分片上传(大文件分片上传速度快么)
- 2025-06-15 js获取上传文件类型以及大小的方法
- 2024-10-04 JAVAWEB 文件上传及下载 java文件的上传和下载
- 2024-10-04 用JAVA实现大文件上传及显示进度信息
- 2024-10-04 常用JSP文件上传,下载的一些方法 常用jsp文件上传,下载的一些方法叫什么
你 发表评论:
欢迎- 527℃Oracle分析函数之Lag和Lead()使用
- 526℃几个Oracle空值处理函数 oracle处理null值的函数
- 523℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 508℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 506℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 497℃【数据统计分析】详解Oracle分组函数之CUBE
- 477℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 475℃Oracle有哪些常见的函数? oracle中常用的函数
- 最近发表
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (61)
- 前端数组 (73)
- 前端排序 (47)
- 前端定时器 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)