zoukankan      html  css  js  c++  java
  • FastApi下载文件

    FastApi下载文件

    记得之前我们讲过生成excel文件的事情,那么如何把服务器生成的excel文件正确发送给用户呢?

    今天我们就来说说在FastApi中如何正确让用户下载到想要的文件。

    基本流程

    其实文件下载的场景还是挺多的,比如我想要拿到我这个用户最近10天创建的测试用例数据,那么我们服务端应该怎么做呢?

    1. 根据条件筛选出正确的数据
    2. 处理数据,生成对应的目标格式文件,比如csv,xlsx等等
    3. 返回http响应,其中指定response的内容和类型

    温馨提示

    现在假设我们已经完成了之前的步骤,并且生成了一个临时文件

    需要注意的是,临时文件的名字为了确保唯一性,最好是用时间戳+随机字符串,或者懒一点可以用uuid

    这里为了方便,我就编写一个简便的方法:

    import time
    import random
    
    random_str = list("abcdefgh")
    random.shuffle(random_str)
    filename = f"{time.time_ns()}_{''.join(random_str)}"
    

    取当前时间戳(精确到纳秒),这时候还是有可能会有同一请求发生,所以我们再用random.shuffle对我们想要加的字符串进行随机排序(打乱顺序)。

    这样一来,文件重名的概率就小了非常多,如果要严谨的话,可以把字符串放长点,但是文件名也会拖很长。

    记得一定要保存这个随机的文件名,并且加上文件后缀哈~!

    FastApi怎么做呢

    其实文件也是HTTP的响应之一,只不过它相对特殊。

    在FastApi中,响应有Response和FileResponse等多种,我们暂时看Response和FileResponse即可。

    Response是我们常见的类型,当然fastapi比较友好,你如果return 一个字典,会默认将之转换为JSON Response。

    但当你要设置返回的http状态码,那就需要去操作这个Response对象了。

    我们常见的比如403 forbidden,401未认证,都可以用Response来实现。


    那么对于FileResponse,我们怎么用呢?

    其实用法比较简单,我们来看实战:

    from fastapi import FastAPI
    from starlette.responses import FileResponse
    
    
    app = FastAPI(name="monitor")
    
    @app.get("/download")
    async def download():
        # 处理完毕文件以后,生成了文件路径
        filename = "你要下载的文件路径.xls"
        return FileResponse(
                filename,  # 这里的文件名是你要发送的文件名
                filename="lol.exe", # 这里的文件名是你要给用户展示的下载的文件名,比如我这里叫lol.exe
            )
    
    

    这样,前端页面提供一个a标签,href地址填对应的接口地址就好了。

    <!DOCTYPE html>
    <html>
    <head>
    	<title>测试</title>
    </head>
    <body>
      <!-- 这个地址用你的host:port加上接口地址-->
    	<a href="http://localhost:7777/download">下载文件</a>
    </body>
    </html>
    

    等等 好像少了点啥

    我们这个生成的文件虽然说都是随机的,没啥影响。但是如果一直有人生成,那不删除真的大丈夫吗?

    所以我们得考虑下怎么删除文件~

    • 理所当然认为try finally

      答案是行不通的,因为finally的内容会在return之前进行。如果这时候你删除了文件,那么Response就返回不了文件了,会报错。

      还好我们FastApi原生提供了background功能,幕后工作人员会在执行完毕之后进行一些暗箱操作

      所以我们可以这么改动:

    from starlette.background import BackgroundTask
    
            return FileResponse(
                filename,
                filename="application.xls",
                background=BackgroundTask(lambda: os.remove(filename)),
            )
    

    使用background接受一个参数BackgroundTask,里面参数是一个无参方法:

    lambda: os.remove(filename)

    也就是删除这个文件的方法。

    最后

    flask的相关文件下载可以看博主几年前写的文章,原理都通用。

    https://www.cnblogs.com/we8fans/p/7107353.html

  • 相关阅读:
    Mybatis批量插入,是否能够返回id列表
    SVN和Git代码管理小结
    SVN和Git代码管理小结
    Spring异步执行(@Async)2点注意事项
    Spring异步执行(@Async)2点注意事项
    2015年工作中遇到的问题101-110
    Codeforces 263B. Appleman and Card Game
    Codeforces 263A. Appleman and Easy Task
    HDU 482 String
    字符串hash-BKDRHash
  • 原文地址:https://www.cnblogs.com/we8fans/p/15545117.html
Copyright © 2011-2022 走看看