最近博客项目有一个需求,博客前端通过mavon-editor上传图片,后端将其保存在数据库中,而这就出现了一个为问题,如何通过FastAPI传输这种文件,以及如何对它编码解码.
对这个问题,我们很容易显出一个很烂简单的做法,将图片直接压缩为base64格式,字符串传输存储,但这样的问题在于,传输的数据量大,处理起来也非常麻烦,而我们从fastapi的官网可以看到,fastapi的响应依赖starlette,那么我们可以再跳转到starlette,看到这一段:
StreamingResponse
Takes an async generator or a normal generator/iterator and streams the response body.
Have in mind that file-like objects (like those created byopen()) are normal iterators. So, you can return them directly in aStreamingResponse.
大意是:使用一个异步的生成器或普通的生成器/可迭代对象作为这个响应主体.请记住,类文件对象(如open()创建的对象)是普通的迭代器。所以,你可以直接以流响应的形式返回它们。
这是非常有帮助的一段信息,让我们再看看官方的实例:
from starlette.responses import StreamingResponse #引入需要的文件
import asyncio
#定义一个异步生成器
async def slow_numbers(minimum, maximum):
yield('<html><body><ul>')
for number in range(minimum, maximum + 1):
yield '<li>%d</li>' % number
await asyncio.sleep(0.5)
yield('</ul></body></html>')
#定义接口,主要部分
async def app(scope, receive, send):
assert scope['type'] == 'http'
generator = slow_numbers(1, 10) #获取生成器
response = StreamingResponse(generator, media_type='text/html') #关键部分!通过生成器生成对象.
await response(scope, receive, send)
根据这个,我们就可以进行代码编写了,我的博客项目使用的是sqlite的blob类型字段存储图像,所以我们要借助io库,并最后返回一个StreamingResponse实例.话不多说,上代码:
@app.get("/asset/img/{imgId}") #定义路径,使用了一个路径参数
async def getImgApi(imgId: int): #定义函数,注意要加上async,其实不加也可以运行,但访问数据库时变为多线程访问,需要设置check_sme_thread=False
img = db.get("files", id=imgId) #获取图像,这里使用了一个自己封装的sqlite3数据库接口,这行代码的意思是,设定img为数据库中从"files"表中获取的id=imgId的数据.
imgD = img.file #获取其中的blob字段的值,也就是说imgD是真正的BLOB字段的值.
buffer = io.BytesIO(imgD) #创建一个BytesIO,因为之前说过,可以使用like-file objects(和文件具有相同接口的对象)作为参数.
r = StreamingResponse(buffer) #创建响应体
return r #返回
这里我们在fastapi中可以直接通过这种方式返回一个starlette的response,因为其官网上说:
Return a
ResponseIn fact, you can return any
Responseor any sub-class of it.
And when you return aResponse, FastAPI will pass it directly.
It won't do any data conversion with Pydantic models, it won't convert the contents to any type, etc.
This gives you a lot of flexibility. You can return any data type, override any data declaration or validation, etc.
也就是说,我们可以直接返回STARLETTE的response,因为Response类其实就是那里面的.
这样我们就实现了一个文件的传输操作.
以上是这篇文章的全部,错误的地方恳请指正.
希望能和大家一起学习.
最后,都看到这了,赞赏一下呗!(^ ~ ^||).