网站首页 > 开源技术 正文
文件上传
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 中。
猜你喜欢
- 2024-10-07 第68节 Ajax-Web前端开发之JavaScript-零点程序员-王唯
- 2024-10-07 在 Flask 中处理表单和用户输入(魔兽世界收到名字叫表单处理提醒的私信)
- 2024-10-07 layer全选反选,弹窗+表单+验证组合代码实例
- 2024-10-07 Typora图片自动上传七牛云图床插件整合
- 2024-10-07 web前端程序员,面试必备9种跨域产生原因和解决方案,附资料
- 2024-10-07 Axios Promise 的 HTTP 库使用详细介绍
- 2024-10-07 Vu3+Ts+Vite2+Pinia 搭建开发脚手架
- 2024-10-07 axios学习教程全攻略(axios入门)
- 2024-10-07 JAVA全栈CMS系统vue图片/视频上传组件,多图上传及删除功能11
- 2024-10-07 手把手详细教程:程序猿必备调试工具postman
你 发表评论:
欢迎- 最近发表
-
- 后端服务太慢?试试这 7 招(后端 服务端 区别)
- 做一个适合二次开发的低代码平台,把程序员从curd中解脱出来-1
- Caffeine缓存 最快缓存 内存缓存(caffeine缓存使用)
- Java性能优化的10大策略(java性能调优从哪几个方面入手)
- New Balance M576PGT 全新配色设计
- x-cmd pkg | qrencode - 二维码生成工具
- 平和精英抽奖概率是多少 平和精英抽奖物品一览
- x-cmd pkg | tmux - 开源终端多路复用器(terminal multiplexer)
- 漫威官方App中文版上线:全站漫画限时免费
- macOS Monterey 12.7.4 (21H1123) 正式版发布,ISO、IPSW、PKG 下载
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)