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 相关文章推荐
详解如何在vue+element-ui的项目中封装dialog组件
Dec 11 Vue.js
如何在vue中使用kindeditor富文本编辑器
Dec 19 Vue.js
vue监听滚动事件的方法
Dec 21 Vue.js
vuex的使用步骤
Jan 06 Vue.js
vue 动态添加的路由页面刷新时失效的原因及解决方案
Feb 26 Vue.js
vue 使用饿了么UI仿写teambition的筛选功能
Mar 01 Vue.js
浅谈vue2的$refs在vue3组合式API中的替代方法
Apr 18 Vue.js
vue2实现provide inject传递响应式
May 21 Vue.js
Vue3中的Refs和Ref详情
Nov 11 Vue.js
详解Vue项目的打包方式(生成dist文件)
Jan 18 Vue.js
VUE中的v-if与v-show区别介绍
Mar 13 Vue.js
vue中的可拖拽宽度div的实现示例
Apr 08 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
PHILIPS AE3805收音机的分析打磨
2021/03/02 无线电
php在项目中寻找代码的坏味道(综艺命名)
2012/07/19 PHP
提升PHP性能的21种方法介绍
2013/06/25 PHP
php实现留言板功能(会话控制)
2017/05/23 PHP
使用JS操作页面表格,元素的一些技巧
2007/02/02 Javascript
Javascript实现仿WebQQ界面的“浮云”兼容 IE7以上版本及FF
2011/04/27 Javascript
javascript椭圆旋转相册实现代码
2012/01/16 Javascript
idTabs基于JQuery的根据URL参数选择Tab插件
2012/04/11 Javascript
Javacript实现颜色梯度变化和渐变的效果代码
2013/05/31 Javascript
js 通过cookie实现刷新不变化树形菜单
2014/10/30 Javascript
JS实现网页Div层Clone拖拽效果
2015/09/26 Javascript
bootstrap table分页模板和获取表中的ID方法
2017/01/10 Javascript
JavaScript数组迭代方法
2017/03/03 Javascript
js + css实现标签内容切换功能(实例讲解)
2017/10/09 Javascript
vue使用rem实现 移动端屏幕适配
2018/09/26 Javascript
微信小程序实现搜索历史功能
2020/03/26 Javascript
vue+Element实现搜索关键字高亮功能
2019/05/28 Javascript
微信小程序官方动态自定义底部tabBar的例子
2019/09/04 Javascript
八种Vue组件间通讯方式合集(推荐)
2020/08/18 Javascript
[01:04:31]DOTA2-DPC中国联赛定级赛 iG vs Magma BO3第二场 1月8日
2021/03/11 DOTA
linux 下实现python多版本安装实践
2014/11/18 Python
Python3数据库操作包pymysql的操作方法
2018/07/16 Python
对numpy中向量式三目运算符详解
2018/10/31 Python
Django开发的简易留言板案例详解
2018/12/04 Python
python实现翻转棋游戏(othello)
2019/07/29 Python
Python中的 ansible 动态Inventory 脚本
2020/01/19 Python
婴儿鞋,独特的婴儿服装和配件:Zutano
2018/11/03 全球购物
如何提高MySql的安全性
2014/06/19 面试题
专科毕业生求职简历的自我评价
2013/10/12 职场文书
农救科工作职责
2013/11/27 职场文书
行政助理岗位职责范文
2013/12/03 职场文书
设计顾问服务计划书
2014/05/04 职场文书
北京离婚协议书范文2014
2014/09/29 职场文书
运动会班级口号霸气押韵
2015/12/24 职场文书
2019年个人工作总结范文
2019/03/25 职场文书
python 机器学习的标准化、归一化、正则化、离散化和白化
2021/04/16 Python