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 Teleport 的实践及原理
Dec 02 Vue.js
vue 动态生成拓扑图的示例
Jan 03 Vue.js
vue3 watch和watchEffect的使用以及有哪些区别
Jan 26 Vue.js
vscode自定义vue模板的实现
Jan 27 Vue.js
如何在vue中使用video.js播放m3u8格式的视频
Feb 01 Vue.js
vue-router路由懒加载及实现的3种方式
Feb 28 Vue.js
Vue详细的入门笔记
May 10 Vue.js
SSM VUE Axios详解
Oct 05 Vue.js
详解Vue项目的打包方式(生成dist文件)
Jan 18 Vue.js
Vue.Draggable实现交换位置
Apr 07 Vue.js
vue实力踩坑之push当前页无效
Apr 10 Vue.js
vue二维数组循环嵌套方式 循环数组、循环嵌套数组
Apr 24 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取整函数:ceil,floor,round,intval的区别详细解析
2013/08/31 PHP
举例讲解PHP面对对象编程的多态
2015/08/12 PHP
mouse_on_title.js
2006/08/25 Javascript
JQuery扩展插件Validate 3通过参数设置错误信息
2011/09/05 Javascript
jquery ready(fn)事件使用介绍
2013/08/21 Javascript
浏览器页面区域大小的js获取方法
2013/09/21 Javascript
javascipt匹配单行和多行注释的正则表达式
2013/11/20 Javascript
jquery ajax跨域解决方法(json方式)
2014/02/04 Javascript
jquery easyui使用心得
2014/07/07 Javascript
JavaScript判断textarea值是否为空并给出相应提示
2014/09/04 Javascript
jquery仿百度经验滑动切换浏览效果
2015/04/14 Javascript
JavaScript简单遍历DOM对象所有属性的实现方法
2015/10/21 Javascript
浅谈JQuery+ajax+jsonp 跨域访问
2016/06/25 Javascript
vue2.0实现倒计时的插件(时间戳 刷新 跳转 都不影响)
2017/03/30 Javascript
JavaScript 中调用 Kotlin 方法实例详解
2017/06/09 Javascript
vue中$refs的用法及作用详解
2018/04/24 Javascript
Angular6 正则表达式允许输入部分中文字符
2018/09/10 Javascript
jQuery事件委托代码实践详解
2019/06/21 jQuery
Vue开发环境跨域访问问题
2020/01/22 Javascript
IDEA配置jQuery, $符号不再显示黄色波浪线的问题
2020/10/09 jQuery
python使用scrapy解析js示例
2014/01/23 Python
用Python代码来解图片迷宫的方法整理
2015/04/02 Python
Python实现截屏的函数
2015/07/26 Python
使用Python处理Excel表格的简单方法
2018/06/07 Python
利用Python将数值型特征进行离散化操作的方法
2018/11/06 Python
Python求两个圆的交点坐标或三个圆的交点坐标方法
2018/11/07 Python
树莓派使用USB摄像头和motion实现监控
2019/06/22 Python
python 牛顿法实现逻辑回归(Logistic Regression)
2020/10/15 Python
python实现测试工具(一)——命令行发送get请求
2020/10/19 Python
项目申请汇报材料
2014/08/16 职场文书
2014年数学教师工作总结
2014/12/03 职场文书
导游词范文
2015/02/13 职场文书
上帝也疯狂观后感
2015/06/09 职场文书
MySQL为id选择合适的数据类型
2021/06/07 MySQL
JS 4个超级实用的小技巧 提升开发效率
2021/10/05 Javascript
WINDOWS下安装mysql 8.x 的方法图文教程
2022/04/19 MySQL