简体   繁体   English

如何使用 ReactJS 在前端使用 Axios 和在后端使用 FastAPI 下载文件?

[英]How to download a file using ReactJS with Axios in the frontend and FastAPI in the backend?

I am trying to create a docx file and send it to the frontend client app, so that it can be downloaded to the user's local machine.我正在尝试创建一个docx文件并将其发送到前端客户端应用程序,以便可以将其下载到用户的本地计算机。 I am using FastAPI for the backend.我在后端使用 FastAPI。 I am using python-docx library also to create the Document .我也在使用python-docx库来创建Document

The code below is used to create a docx file and save it to the server.下面的代码用于创建一个docx文件并将其保存到服务器。

@app.post("/create_file")
async def create_file(data: Item):
    document = Document()
    document.add_heading("file generated", level=1)
    document.add_paragraph("test")
    document.save('generated_file.docx')
    return {"status":"Done!"}

The below code is then used to send the created docx file as a FileResponse to the client.然后使用下面的代码将创建的docx文件作为FileResponse发送到客户端。

@app.get("/generated_file")
async def download_generated_file():
    file_path = "generated_file.docx"
    return FileResponse(file_path, media_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document', filename=file_path)

On Client side (I am using ReactJS):在客户端(我正在使用 ReactJS):

createFile = async () => {
   const data = {
      start: this.state.start,
      end: this.state.end,
      text: this.state.text,
   };
   await axios.post("http://localhost:8000/create_file", data).then(() => {
      console.log("processing completed!");
   });
};

downloadFile = async () => {
   await axios.get("http://localhost:8000/generated_file").then((res) => {
      const url = URL.createObjectURL(new Blob([res.data]));
      const link = document.createElement("a");
      link.href = url;
      link.setAttribute("download", "generated.txt");
      link.click();
   });
};

The generated.docx file gets downloaded when downloadFile function is called.调用downloadFile function 时会下载generated.docx的.docx 文件。 However, the docx file is always corrupted and doesn't open.但是, docx文件总是损坏并且无法打开。 I tried using txt file and it works fine.我尝试使用 txt 文件,它工作正常。 I need to use docx file, so what can I do?我需要使用docx文件,我该怎么办?

In the Axios GET request, you have to make sure the responseType parameter is set to blob .在 Axios GET请求中,您必须确保responseType参数设置为blob Once you get the response from the API, you will need to pass the response.data to the URL.createObjectURL() function.从 API 获得response后,您需要将response.data传递给URL.createObjectURL() function。 Below is a fully working example on how to create and download a file ( Document ), using either Axios or Fetch API in the frontend.下面是一个关于如何创建和下载文件( Document )的完整示例,在前端使用 Axios 或 Fetch API。 This answer utilises methods and code excerpts from this and this answer, as well as the answers here and here .这个答案利用了这个这个答案的方法和代码摘录,以及这里这里的答案。 Plesase refer to the above answers for more details on the methods used below.有关以下使用的方法的更多详细信息,请参阅上述答案。 For demo purposes, the below example uses Jinja2Templates , but, in a similar way, you can use the scripts below in your ReactJS app.出于演示目的,以下示例使用Jinja2Templates ,但以类似的方式,您可以在 ReactJS 应用程序中使用以下脚本。

app.py应用程序.py

from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import FileResponse
from docx import Document

app = FastAPI()
templates = Jinja2Templates(directory="templates")


@app.get('/')
def main(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})
    
@app.post("/create")
def create_file():
    document = Document()
    document.add_heading("file generated", level=1)
    document.add_paragraph("test")
    document.save('generated_file.docx')
    return {"status":"Done!"}
    
@app.get("/download")
def download_generated_file():
    file_path = "generated_file.docx"
    return FileResponse(file_path, media_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document', filename=file_path)

Using Axios使用 Axios

tempaltes/ index.htnl模板/ index.htnl

<!DOCTYPE html>
<html>
   <head>
      <title>Create and Download a Document</title>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.27.2/axios.min.js"></script>
   </head>
   <body>
      <input type="button" value="Create Document" onclick="createFile()">
      <div id="response"></div><br>
      <input type="button" value="Download Document " onclick="downloadFile()">
      <script>
         function createFile() {
            axios.post('/create', {
                  headers: {
                     'Accept': 'application/json',
                     'Content-Type': 'application/json'
                  }
               })
               .then(response => {
                  document.getElementById("response").innerHTML = JSON.stringify(response.data);
               })
               .catch(error => {
                  console.error(error);
               });
         }
         
         function downloadFile() {
            axios.get('/download', {
                  responseType: 'blob'
               })
               .then(response => {
                  const disposition = response.headers['content-disposition'];
                  filename = disposition.split(/;(.+)/)[1].split(/=(.+)/)[1];
                  if (filename.toLowerCase().startsWith("utf-8''"))
                     filename = decodeURIComponent(filename.replace("utf-8''", ''));
                  else
                     filename = filename.replace(/['"]/g, '');
                  return response.data;
               })
               .then(data => {
                  var url = window.URL.createObjectURL(data);
                  var a = document.createElement('a');
                  a.href = url;
                  a.download = filename;
                  document.body.appendChild(a); // append the element to the dom
                  a.click();
                  a.remove(); // afterwards, remove the element  
               })
               .catch(error => {
                  console.error(error);
               });
         }
      </script>
   </body>
</html>

Using Fetch API使用 Fetch API

tempaltes/ index.htnl模板/ index.htnl

<!DOCTYPE html>
<html>
   <head>
      <title>Create and Download a Document</title>
   </head>
   <body>
      <input type="button" value="Create Document" onclick="createFile()">
      <div id="response"></div><br>
      <input type="button" value="Download Document" onclick="downloadFile()">
      <script>
         function createFile() {
            fetch('/create', {
                  method: 'POST',
                  headers: {
                     'Accept': 'application/json',
                     'Content-Type': 'application/json'
                  }
               })
               .then(response => response.text())
               .then(data => {
                  document.getElementById("response").innerHTML = data;
               })
               .catch(error => {
                  console.error(error);
               });
         }
         
         function downloadFile() {
            fetch('/download')
               .then(response => {
                  const disposition = response.headers.get('Content-Disposition');
                  filename = disposition.split(/;(.+)/)[1].split(/=(.+)/)[1];
                  if (filename.toLowerCase().startsWith("utf-8''"))
                     filename = decodeURIComponent(filename.replace("utf-8''", ''));
                  else
                     filename = filename.replace(/['"]/g, '');
                  return response.blob();
               })
               .then(blob => {
                  var url = window.URL.createObjectURL(blob);
                  var a = document.createElement('a');
                  a.href = url;
                  a.download = filename;
                  document.body.appendChild(a); // append the element to the dom
                  a.click();
                  a.remove(); // afterwards, remove the element
               })
               .catch(error => {
                  console.error(error);
               });
         }
      </script>
   </body>
</html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM