vue + djangorestframework實現文件下載功能
1.安裝模塊及配置及配置
先安裝django-cors-headers包
pip3 install djangorestframework django-cors-headers
在setting文件中註冊app
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'api.apps.ApiConfig', 'corsheaders', # 注册应用cors ]
在setting文件中註冊中間件
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'corsheaders.middleware.CorsMiddleware', # 注册组件cors ]
配置置請求方法與請求頭部信息
CORS_ALLOW_METHODS = ( 'GET', 'OPTIONS', 'PATCH', 'POST', 'VIEW', ) CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', )
2.添加路由與方法
路由
from django.contrib import admin from django.urls import path from api import views urlpatterns = [ path('admin/', admin.site.urls), path('downloadFile/', views.Download.as_view()), ]
視圖
class Download(DispatchMethod,APIView): def post(self, request): file_name = request.data.get('file_name') file_path = request.data.get('file_path') connKey = request.data.get("connKey") hostname = request.data.get("hostname") login_key = request.data.get("login_key") program_id = request.data.get("program_id") stime = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) language = getLanguage(request) data = checkToken(request) if data.get("status") > 0: bu = UmbResourceBll(connKey) data = bu.getFileObj(file_name,file_path,language) WriteApiLog(stime, program_id, login_key, hostname, "[method:post]", self) if data.get("status"): return JsonResponse(data, status=200) return data else: return JsonResponse(data, status=401) class UmbResourceBll(object): def __init__(self, connkey=k_ov.local_db_id): self.dbConnKey = baseUtils.checkConnkey(connkey) self.ud = UmbResourceDal() self.ulang = langUtils() def response_param(self, response_code, response_msg, language=None, error_log=None): if language: if response_code == -99: sMessage = self.ulang.getMSG(response_msg, language) + str(error_log) else: sMessage = self.ulang.getMSG(response_msg, language) else: sMessage = response_msg return response_code, sMessagedef getFileObj(self, file_name, file_path, language): status = 0 sMessage = "" rows = [] try: # StreamingHttpResponse 流式響應,内容的迭代器形式,以内容流的方式响应 file_obj = StreamingHttpResponse(self.file_iterator(file_path)) file_obj['Content-Type'] = 'application/octet-stream' file_obj['Access-Control-Expose-Headers'] = "Content-Disposition, Content-Type" # escape_uri_path防止文件是中文名出現亂碼 file_obj['Content-Disposition'] = "attachment; filename={}".format(escape_uri_path(file_name)) # status, sMessage = self.response_param(2, 'UW_0120', language) return file_obj except Exception as e: status, sMessage = self.response_param(-99, 'AM_0008', language, error_log=e) return {"rows": rows, "status": status, "message": sMessage} @staticmethod def file_iterator(file_path, chunk_size=512): """ 讀出文件 以rb的形式 文件生成器,防止文件過大,導致內存溢出 :param file_path: 文件絕對路勁 :param chunk_size: 每次讀出的大小 :return: """ with open(file_path, 'rb') as f: while True: content = f.read(chunk_size) if content: yield content else: break
3.前端展示及獲取邏輯
template
<template> <div class="right-button"> <div class="right-button"> <el-row style="margin-left:10px"> <el-button size="mini" icon="el-icon-view" type="primary" @click="showFiles">{{$t("視圖")}}</el-button> <el-button size="mini" icon="el-icon-folder-opened" @click="downloadFile" type="success">{{$t("下載")}}</el-button> </el-row> </div> </div> </template>
script
// 下載指定的文件 downloadFile(){ // 從session中獲取被點擊的主table行數據 let current_row = window.sessionStorage.getItem("nowRow") current_row = eval('('+current_row+')') if(!current_row.file_name){ return } DownloadFileParames.file_name = current_row.file_name DownloadFileParames.file_path = current_row.file_path DownloadFileParames.connKey = this.$store.state.now_conn_key let file_type return new Promise((resolve, reject) =>{ this.$http.post(apiDownloadFile,DownloadFileParames,{ "headers": { 'Authorization': "jwt " + window.localStorage.getItem("token") }, "responseType": "blob" }).then( response => { resolve(response.data) // 根據文件後綴設置文件流的文件類型 if(DownloadFileParames.file_name.endsWith("pdf")){ file_type = "application/pdf" }else if(DownloadFileParames.file_name.endsWith("mp4")){ file_type = "video/mpeg4" } let blob = new Blob([response.data], { type:file_type }) // 文件名 let fileNameEncode = response.headers['content-disposition'].split("filename=")[1] // 解码 函数可把字符串作为 URI 组件进行解码 let fileName = decodeURIComponent(fileNameEncode) // msSaveBlob和msSaveOrOpenBlob 方法允许用户在客户端上保存文件 // window.navigator 对象包含有关访问者浏览器的信息 if (window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, fileName) } else { // 創建a標籤 var link = document.createElement('a') // 設置a標籤鏈接 link.href = window.URL.createObjectURL(blob) // 將文件名賦值給a標籤的下載屬性并觸發點擊 link.download = fileName link.click() //释放内存 window.URL.revokeObjectURL(link.href) } }, err => { reject(this.$message({ showClose: false, message: res.data.message, type: 'error', duration: 2000 })) } ) }) }