如何将Base64编码图像发送到FastAPI后端

发布时间:2022-09-22 / 作者:清心寡欲
本文介绍了如何将Base64编码图像发送到FastAPI后端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用this和that answer中的代码将一个Base64编码的图像发送到一个python FastAPI后端。客户端如下所示:

function toDataURL(src, callback, outputFormat) {
            var img = new Image();
            img.crossOrigin = 'Anonymous';
            img.onload = function() {
                var canvas = document.createElement('CANVAS');
                var ctx = canvas.getContext('2d');
                var dataURL;
                canvas.height = this.naturalHeight;
                canvas.width = this.naturalWidth;
                ctx.drawImage(this, 0, 0);
                dataURL = canvas.toDataURL(outputFormat);
                callback(dataURL);
            };
            img.src = src;
            if (img.complete || img.complete === undefined) {
                img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
                img.src = src;
            }
        }

        function makeBlob(dataURL) {
            var BASE64_MARKER = ';base64,';
            if (dataURL.indexOf(BASE64_MARKER) == -1) {
                var parts = dataURL.split(',');
                var contentType = parts[0].split(':')[1];
                var raw = decodeURIComponent(parts[1]);
                return new Blob([raw], { type: contentType });
            }
            var parts = dataURL.split(BASE64_MARKER);
            var contentType = parts[0].split(':')[1];
            var raw = window.atob(parts[1]);
            var rawLength = raw.length;

            var uInt8Array = new Uint8Array(rawLength);

            for (var i = 0; i < rawLength; ++i) {
                uInt8Array[i] = raw.charCodeAt(i);
            }

            return new Blob([uInt8Array], { type: contentType });
        }

        ...

        toDataURL(
            images[0], // images is an array of paths to images
            function(dataUrl) {
                console.log('RESULT:', dataUrl);

                $.ajax({
                    url: "http://0.0.0.0:8000/check/",
                    type: 'POST',
                    processData: false,
                    contentType: 'application/octet-stream',
                    data: makeBlob(dataUrl)
                }).done(function(data) {console.log("success");}).fail(function() {console.log("error");});
            }
        );

服务器端如下:

@app.post("/check")
async def check(file: bytes = File(...)) -> Any:  
    // do something here

我仅显示终结点的签名,因为目前它中没有发生任何事情。

下面是我如上所示调用后端时的输出:

172.17.0.1:36464-选项/Check/Http/1.1&Quot;200

172.17.0.1:36464-POST/CHECK/Http/1.1307

172.17.0.1:36464-选项/检查Http/1.1200

172.17.0.1:36464-POST/Check Http/1.1&q;422

简而言之,我一直收到422个错误代码,这意味着我发送的内容与端点期望的内容不匹配,但即使经过一些阅读,我仍然不清楚问题到底是什么。我们非常欢迎您的帮助!

推荐答案

作为previously mentioned,上传的文件作为form数据发送。根据FastAPI documentation:

来自表单的数据通常使用";媒体类型";进行编码 application/x-www-form-urlencoded当它不包括文件时。

如果表单包含文件,则编码为 multipart/form-data。如果您使用File,FastAPI将知道它必须 来自正文正确部分的文件。

无论您使用什么类型,bytesUploadFile,因为...

如果将路径运算函数参数的类型声明为 bytesFastAPI将为您读取文件,您将收到 以字节为单位的内容。

因此,422无法处理实体错误。在您的示例中,您发送的是二进制数据(使用application/octet-streamforcontent-type),但是您的API的终结点需要form数据(即multipart/form-data)。

选项1

不发送Base64编码的图像,而是按原样上传文件,要么使用here所示的HTML表单,要么使用如下所示的Java脚本。正如其他人指出的,在使用JQuery时,it is imperative that you set the contentType option to false。对于纯Java脚本,如下所示(方法为credits),手动设置content-type时会出现上述链接中描述的类似问题;因此,最好将其省略,并强制浏览器设置它(以及强制的multipart boundary)。

服务器端

@app.post("/upload")
async def upload(file: UploadFile = File(...)):
    with open("uploaded_" + file.filename, "wb") as f:
        contents = await file.read()
        f.write(contents)
        
    return file.filename

客户端:


 

如果您希望使用Axios库进行上传,请查看this answer。

选项2

如果您还需要上传Base64编码的图片,您可以将数据作为form数据发送,使用application/x-www-form-urlencoded作为content-type;而在您的API的端点,您可以定义一个Form字段来接收数据。下面是一个完整的工作示例,其中服务器发送、接收、解码并保存到磁盘上的Base64编码图像。对于Base64编码,在客户端使用readAsDataURL方法。请注意,文件写入磁盘是使用同步写入完成的。在需要保存多个(或大)文件的情况下,最好使用async写入,如here所述。

app.py

from fastapi import Form, Request, FastAPI
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
import base64

app = FastAPI()

templates = Jinja2Templates(directory="templates")

@app.post("/upload")
async def upload(filename: str = Form(...), filedata: str = Form(...)):
    image_as_bytes = str.encode(filedata)  # convert string to bytes
    png_recovered = base64.b64decode(image_as_bytes)  # decode base64string
    with open("uploaded_" + filename, "wb") as f:
        f.write(png_recovered)
        
    return filename


@app.get("/")
def main(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

模板/index.html



Image preview...

这篇关于如何将Base64编码图像发送到FastAPI后端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持吉威生活!



[英文标题]How to send a base64 encoded image to a FastAPI backend


声明:本媒体部分图片、文章来源于网络,版权归原作者所有,如有侵权,请联系QQ:330946442删除。