如何在 fastAPI 中为 <input type="file"> 定义一个 REST 端点(并使其与 Angular 一起使用)?

Posted

技术标签:

【中文标题】如何在 fastAPI 中为 <input type="file"> 定义一个 REST 端点(并使其与 Angular 一起使用)?【英文标题】:How to define a REST endpoint in fastAPI for <input type="file"> (and make it work with angular)? 【发布时间】:2021-12-30 20:52:19 【问题描述】:

我正在这样做angular tutorial。我正在尝试使用 python fastAPI 创建一个后端端点,该端点通过 HttpClient POST 接收数据,但我正在努力这样做。 (角度 13.0.2,python 3.7,fastapi 0.70.0)

html模板代码:

<input type="file" class="file-input" (change)="onFileSelected($event)" #fileUpload> 

<div class="file-upload">

    fileName || "No file uploaded yet."

    <button mat-mini-fab color="primary" class="upload-btn" (click)="fileUpload.click()">
        <mat-icon>attach_file</mat-icon>
    </button>
</div>

对应组件ts代码:

  onFileSelected(event) 

    const file: File = event.target.files[0]
    console.log(`onFileSelected($file.name)`)

    if (file) 
      this.fileName = file.name;
      const formData = new FormData();
      formData.append("thumbnail", file);
      const upload$ = this.http.post("http://localhost:8000/thumbnail-upload", formData);
      upload$.subscribe();
      console.log("upload done?")
  

fastapi 代码:灵感来自this

@app.post("/thumbnail-upload")
def create_file(file: UploadFile = File(...)):
    print(file)
    return "file_size": len(file)

似乎正在进行一些正常的通信,但我被困在这里:

uvicorn 服务器的输出:

←[32mINFO←[0m:     127.0.0.1:18231 - "←[1mPOST /thumbnail-upload   HTTP/1.1←[0m" ←[31m422 Unprocessable Entity←[0m

浏览器调试控制台中的输出:

zone.js:2863 POST http://localhost:8000/thumbnail-upload 422 (Unprocessable Entity)
core.mjs:6495 ERROR HttpErrorResponse headers: HttpHeaders, status: 422, statusText: 'Unprocessable Entity', url: 'http://localhost:8000/thumbnail-upload', ok: false, …

我需要如何实现 fastAPI 端点才能使其运行? 免责声明:我对 angular/fastapi 很陌生,如果我忘记包含必要的信息,请。告诉我缺少什么;)

【问题讨论】:

【参考方案1】:

422 错误消息的正文将准确地告诉您缺少的字段。从您的代码看来,您正在以 thumbnail 名称提交文件,但您在 FastAPI 路由中使用了 file 名称。由于这两个不匹配,FastAPI 找不到您假设的文件存在。将表单参数重命名为 file 或将 FastAPI 参数重命名为 thumbnail

@app.post("/thumbnail-upload")
def create_file(thumbnail: UploadFile = File(...)):
    print(thumbnail)
    return "file_size": len(thumbnail.file.read())

UploadFile 对象还公开了file 以与幕后的假脱机文件进行交互。由于它不会直接为您提供字节,因此我认为在其上调用 len 不会达到您的预期。

【讨论】:

好的,这就行了。玩弄,我发现formData.append("file", file, file.name); 也适用于我的第一个实现(是的,len(file) 抛出了一个错误)。你能解释一下参数名称在 fastAPI 中的重要性吗?是不是因为 formdata 以键/值形式出现,然后被视为 kwarg? 一个表单可以包含多个文件,可以使用相同的名称或不同的名称。参数名称需要与 FastAPI 匹配,以了解数据与哪个文件相关,并知道它实际上是预期的参数,而不是随机的。如果您使用过查询参数,可能会更清楚; user_id=38 突然匹配 hits: int 会给你各种奇怪的结果。

以上是关于如何在 fastAPI 中为 <input type="file"> 定义一个 REST 端点(并使其与 Angular 一起使用)?的主要内容,如果未能解决你的问题,请参考以下文章

FastAPI Web框架 [依赖项]

如何在 Codeception 验收测试中为 <input type="email"> 获取 WebGuy->fillField?

在一个 <Input> 标签中为多个按钮创建多个 ID

如何在 Angular 中为自定义组件实现伪事件?

FastAPI 中的会话

如何在fastapi中获取多个表单输入字段作为字典?