vue+django實現下載文件


一、概述

在項目中,點擊下載按鈕,就可以下載文件。

傳統的下載鏈接一般是get方式,這種鏈接是公開的,可以任意下載。

在實際項目,某些下載鏈接,是私密的。必須使用post方式,傳遞正確的參數,才能下載。

 

二、django項目

本環境使用django 3.1.5,新建項目download_demo

 

安裝模塊

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)
View Code

 

在項目根目錄創建upload文件

 

 里面放一個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>
View Code

注意:這里使用post請求,並將filename傳輸給api,用來下載指定的文件。 

 

訪問測試頁面,點擊下載按鈕

 

 就會自動下載

 

打開工具欄,查看響應信息

 

這里,就是django返回的文件名,瀏覽器下載保存的文件名,也是這個。

遇到中文,會進行URLcode編碼。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM