vue+django实现下载文件的示例


Posted in Vue.js onMarch 24, 2021

一、概述

在项目中,点击下载按钮,就可以下载文件。

传统的下载链接一般是get方式,这种链接是公开的,可以任意下载。

在实际项目,某些下载链接,是私密的。必须使用post方式,传递正确的参数,才能下载。

二、django项目

本环境使用django 3.1.5,新建项目download_demo

vue+django实现下载文件的示例

安装模块

pip3 install djangorestframework django-cors-headers

修改文件download_demo/settings.py

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
]

注册中间件

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_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
 
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',
)

修改download_demo/urls.py

from django.contrib import admin
from django.urls import path
from api import views
 
urlpatterns = [
 path('admin/', admin.site.urls),
 path('download/excel/', views.ExcelFileDownload.as_view()),
]

修改api/views.py

from django.shortcuts import render,HttpResponse
from download_demo import settings
from django.utils.encoding import escape_uri_path
from django.http import StreamingHttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework import status
import os
 
class ExcelFileDownload(APIView):
 def post(self,request):
  print(request.data)
  # filename = "大江大河.xlsx"
  filename = request.data.get("filename")
  download_file_path = os.path.join(settings.BASE_DIR, "upload",filename)
  print("download_file_path",download_file_path)
 
  response = self.big_file_download(download_file_path, filename)
  if response:
   return response
 
  return JsonResponse({'status': 'HttpResponse', 'msg': 'Excel下载失败'})
 
 def file_iterator(self,file_path, chunk_size=512):
  """
  文件生成器,防止文件过大,导致内存溢出
  :param file_path: 文件绝对路径
  :param chunk_size: 块大小
  :return: 生成器
  """
  with open(file_path, mode='rb') as f:
   while True:
    c = f.read(chunk_size)
    if c:
     yield c
    else:
     break
 
 def big_file_download(self,download_file_path, filename):
  try:
   response = StreamingHttpResponse(self.file_iterator(download_file_path))
   # 增加headers
   response['Content-Type'] = 'application/octet-stream'
   response['Access-Control-Expose-Headers'] = "Content-Disposition, Content-Type"
   response['Content-Disposition'] = "attachment; filename={}".format(escape_uri_path(filename))
   return response
  except Exception:
   return JsonResponse({'status': status.HTTP_400_BAD_REQUEST, 'msg': 'Excel下载失败'},
        status=status.HTTP_400_BAD_REQUEST)

在项目根目录创建upload文件

vue+django实现下载文件的示例

 里面放一个excel文件,比如:大江大河.xlsx

三、vue项目

新建一个vue项目,安装ElementUI 模块即可。

新建test.vue

<template>
 <div style="width: 70%;margin-left: 30px;margin-top: 30px;">
 <el-button class="filter-item" type="success" icon="el-icon-download" @click="downFile()">下载</el-button>
 </div>
</template>
 
<script>
 import axios from 'axios'
 
 export default {
 data() {
  return {
  }
 },
 mounted: function() {
 
 },
 methods: {
  downloadFile(url, options = {}){
  return new Promise((resolve, reject) => {
   // console.log(`${url} 请求数据,参数=>`, JSON.stringify(options))
   // axios.defaults.headers['content-type'] = 'application/json;charset=UTF-8'
   axios({
   method: 'post',
   url: url, // 请求地址
   data: options, // 参数
   responseType: 'blob' // 表明返回服务器返回的数据类型
   }).then(
   response => {
    // console.log("下载响应",response)
    resolve(response.data)
    let blob = new Blob([response.data], {
    type: 'application/vnd.ms-excel'
    })
    // console.log(blob)
    // let fileName = Date.parse(new Date()) + '.xlsx'
    // 切割出文件名
    let fileNameEncode = response.headers['content-disposition'].split("filename=")[1];
    // 解码
    let fileName = decodeURIComponent(fileNameEncode)
    // console.log("fileName",fileName)
    if (window.navigator.msSaveOrOpenBlob) {
    // console.log(2)
    navigator.msSaveBlob(blob, fileName)
    } else {
    // console.log(3)
    var link = document.createElement('a')
    link.href = window.URL.createObjectURL(blob)
    link.download = fileName
    link.click()
    //释放内存
    window.URL.revokeObjectURL(link.href)
    }
   },
   err => {
    reject(err)
   }
   )
  })
  },
  // 下载文件
  downFile(){
  let postUrl= "http://127.0.0.1:8000/download/excel/"
  let params = {
   filename: "大江大河.xlsx",
  }
  // console.log("下载参数",params)
  this.downloadFile(postUrl,params)
  },
 }
 }
</script>
 
<style>
</style>

注意:这里使用post请求,并将filename传输给api,用来下载指定的文件。 

访问测试页面,点击下载按钮

vue+django实现下载文件的示例

就会自动下载

vue+django实现下载文件的示例

打开工具栏,查看响应信息

vue+django实现下载文件的示例

这里,就是django返回的文件名,浏览器下载保存的文件名,也是这个。

遇到中文,会进行URLcode编码。

所以在vue代码中,对Content-Disposition做了切割,得到了文件名。

Vue.js 相关文章推荐
深入了解Vue3模板编译原理
Nov 19 Vue.js
Vue 的 v-model用法实例
Nov 23 Vue.js
Vue与React的区别和优势对比
Dec 18 Vue.js
vue中watch的用法汇总
Dec 28 Vue.js
如何在 Vue 中使用 JSX
Feb 14 Vue.js
vue实现桌面向网页拖动文件的示例代码(可显示图片/音频/视频)
Mar 01 Vue.js
vue项目实现分页效果
Mar 24 Vue.js
如何理解Vue简单状态管理之store模式
May 15 Vue.js
Vue Element UI自定义描述列表组件
May 18 Vue.js
Vue.Draggable实现交换位置
Apr 07 Vue.js
使用vue判断当前环境是安卓还是IOS
Apr 12 Vue.js
vue如何清除浏览器历史栈
May 25 Vue.js
vue路由实现登录拦截
vue项目实现分页效果
Mar 24 #Vue.js
vue实现倒计时功能
Mar 24 #Vue.js
vue 中 get / delete 传递数组参数方法
Mar 23 #Vue.js
使用Vue.js和MJML创建响应式电子邮件
vue+flask实现视频合成功能(拖拽上传)
Mar 04 #Vue.js
vue打开新窗口并实现传参的图文实例
Mar 04 #Vue.js
You might like
配置最新的PHP加MYSQL服务器
2006/10/09 PHP
PHP面试题之文件目录操作
2015/10/15 PHP
PHP自定义递归函数实现数组转JSON功能【支持GBK编码】
2018/07/17 PHP
总结PHP中初始化空数组的最佳方法
2019/02/13 PHP
Mootools 1.2教程 滚动条(Slider)
2009/09/15 Javascript
js不能获取隐藏的div的宽度只能先显示后获取
2014/09/04 Javascript
jQuery插件Tooltipster实现漂亮的工具提示
2015/04/12 Javascript
jQuery实现页面顶部显示的进度条效果完整实例
2015/12/09 Javascript
基于canvas实现的绚丽圆圈效果完整实例
2016/01/26 Javascript
JS 拼凑字符串的简单实例
2016/09/02 Javascript
Vue.js 父子组件通讯开发实例
2016/09/06 Javascript
常用jQuery选择器汇总
2017/02/02 Javascript
详解闭包解决jQuery中AJAX的外部变量问题
2017/02/22 Javascript
node使用UEditor富文本编辑器的方法实例
2017/07/11 Javascript
Vue.js 父子组件通信的十种方式
2018/10/30 Javascript
vuex根据不同的用户权限展示不同的路由列表功能
2019/09/20 Javascript
微信小程序实现电子签名功能
2020/07/29 Javascript
openlayers4实现点动态扩散
2020/08/17 Javascript
给你选择Python语言实现机器学习算法的三大理由
2017/11/15 Python
Python插件virtualenv搭建虚拟环境
2017/11/20 Python
Python实现快速傅里叶变换的方法(FFT)
2018/07/21 Python
python实现二维插值的三维显示
2018/12/17 Python
python 利用pyttsx3文字转语音过程详解
2019/09/25 Python
python自动化实现登录获取图片验证码功能
2019/11/20 Python
python 实现批量替换文本中的某部分内容
2019/12/13 Python
使用Python防止SQL注入攻击的实现示例
2020/05/21 Python
英国男女奢华内衣和泳装购物网站:Figleaves
2017/01/28 全球购物
adidas官方旗舰店:德国运动用品制造商
2017/11/25 全球购物
LN-CC中国:高端男装和女装的奢侈时尚目的地
2019/09/14 全球购物
体育教育专业毕业生自荐信
2013/11/15 职场文书
服务行业个人求职的自我评价
2013/12/12 职场文书
《小池塘》教学反思
2014/02/28 职场文书
2015年为民办实事工作总结
2015/05/26 职场文书
二年级作文之动物作文
2019/11/13 职场文书
php去除deprecated的实例方法
2021/11/17 PHP
Python中的嵌套循环详情
2022/03/23 Python