04-28 周日 FastAPI Post请求同时传递文件和普通参数

news2025/1/13 10:13:48
04-28 周日 FastAPI Post请求同时传递文件和普通参数
时间版本修改人描述
04-28 周日V0.1宋全恒新建文档
2024年5月6日14:20:05V1.0宋全恒完成文档的传递

简介

 由于在重构FastBuild的时候,为了支持TLS是否启用,在接口中需要同时传递文件参数和其他参数,遇到了这个问题。结果发现由于HTTP的限制,不能同时传递JSON和文件参数。当时花费了较多的实践,因此记录了如下的过程。

代码示例

使用Form表单形式

 使用Form表单参数,可以实现,同时结合使用UploadFile可以非常方便。

@router.post("/update-docker-server")
async def update_docker_server_config(host: str = Form(), port: int = Form(), tls_tar_file: UploadFile = File(None)):
    if not validate_host(host):
        return Response.error(f"请输入有效的ip或者域名,参数host: {host}")

    new_docker_server = DBDockerServer(
        host=host,
        port=port,
        tls_verify=False
    )
    tls_verify = False
    if tls_tar_file:
        tls_folder_name = get_ip_address_folder(host)

 在相应的swagger页面上,显示如下所示:

image-20240428112217317

同时传递文件和对象参数

如何在FastAPI POST请求中同时添加文件和JSON主体?

image-20240506141857494

 由于上述的HTTP限制,因此,无法在维持JSON的结构的同时传递文件参数。

如here所述,用户可以使用FileForm字段同时定义文件和表单数据。

@router.post("/update-docker-server-in-object")
async def update_docker_server_config_in_object(
        docker_server_request: DockerServerRequest = Depends(docker_server_request_checker),
        tls_tar_file: UploadFile = File(None)):
    print(docker_server_request.host)

 docker_server_request_checker的定义如下:

from http.client import HTTPException

from fastapi import Form, status
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel, ValidationError


class DockerServerRequest(BaseModel):
    host: str
    port: int = 2375


def docker_server_request_checker(data: str = Form(...)):
    try:
        model = DockerServerRequest.parse_raw(data)
    except ValidationError as e:
        raise HTTPException(
            detail=jsonable_encoder(e.errors()),
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        )
    return model

image-20240428144212784

 对于一个比较复杂的data参数,其中多层嵌套也是比较难写的。因为要手动生成这个结构,倒是不如直接使用Form表单化每个数据,第三方调用这个接口的时候,由于key是不用留心的,这样在传递参数的时候,不需要过多的注意力。

最后的实践

 由于FastBuild工程在运行时需要提前配置好容器所在的宿主机IP,Harbor的用户名和密码,Docker服务器(两种情形,一种是Docker启用了TLS,则需要上传文件tls-client-certs-jenkins.tar.gz, 另外则是普通的Docker服务),为了满足这多种情况,尤其是对于TLS的灵活性,因此最终选择了第一种方案,即使用多个Form参数以及文件参数的方式来完成对于FastBuild的统一配置接口

Controller

@router.post("/config-fastbuild")
async def update_docker_server_config_in_object(
        fastbuild_host: str = Form(), fastbuild_port: int = Form(default=48001),
        harbor_username: str = Form(), harbor_password: str = Form(), harbor_registry: str = Form(),
        harbor_registry_dns: str = Form(default=''),
        docker_host: str = Form(), docker_port: int = Form(default=2375), docker_tls_tar_file: UploadFile = File(None)):
    print("fastbuild: ", fastbuild_host, fastbuild_port)
    print("harbor: ", harbor_username, harbor_password, harbor_registry, harbor_registry_dns)

    if not all(map(validate_host, [fastbuild_host, harbor_registry, harbor_registry_dns, docker_host])):
        return Response.error(data="fastbuild_host, harbor_registry_host, harbor_registry_dns, docker_host均应为有效的ip或者域名")

    db_host = DBHost(host_ip=fastbuild_host, host_port=fastbuild_port)
    db_harbor = DBHarbor(username=harbor_username, password=harbor_password, registry=harbor_registry, registry_dns=harbor_registry_dns)
    db_docker = DBDockerServer(host=docker_host, port=docker_port, tls_verify=False)
    if docker_tls_tar_file:
        tls_folder_name = get_ip_address_folder(db_docker.host)
        tls_dir = save_and_extract_tar(docker_tls_tar_file, system_config.get_tls_dir(), tls_folder_name)
        tls_files = ["ca-jenkins.pem", "cert-jenkins.pem", "key-jenkins.pem"]
        if not all(file in get_files_in_directory(tls_dir) for file in tls_files):
            return Response.error(f"请上传正确的tls文件,当前上传的文件为{docker_tls_tar_file.filename},解压后不包含{' '.join(tls_files)}")

        db_docker.tls_verify = True
        db_docker.client_cert_path = os.path.join(tls_dir, "cert-jenkins.pem")
        db_docker.ca_path = os.path.join(tls_dir, "ca-jenkins.pem")
        db_docker.client_key_path = os.path.join(tls_dir, "key-jenkins.pem")
    try:
        image_utils = ImageUtils(db_docker, db_harbor)
    except DockerException as exe:
        print(f"发生异常: {exe}")
        raise FBException(code=123, message=f"使用提供的docker和harbor信息,进行登录测试,测试失败,请检查,错误信息为{str(exe)}")

    DBHostService.save(db_host)
    DBHarborService.save(db_harbor)
    DBDockerServerService.save(db_docker)

    return Response.success(data="成功完成为FastBuild配置需要的宿主机信息,Docker信息以及Harbor信息")

 其中validate_host用于判断输入的字符串是一个有效的ip或者域名,具体定义如下:

def validate_host(host: str):
    # 匹配 IP 地址的正则表达式
    ip_pattern = r"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$"
    # 匹配域名地址的正则表达式
    domain_pattern = r"^(?!:\/\/)([a-zA-Z0-9-_]+\.)*[a-zA-Z0-9][a-zA-Z0-9-_]+(\.[a-zA-Z]{2,11})$"

    # 尝试匹配 IP 地址和域名地址的正则表达式
    if re.match(ip_pattern, host) or re.fullmatch(domain_pattern, host):
        return True  # 主机地址合法
    else:
        return False  # 主机地址不合法

 而get_ip_address_folder则是用来根据ip地址获取对应的一个目录,其中包含了一个6位的随机数字

def get_ip_address_folder(ip: str):
    """
    将 IP 地址或域名转换为文件夹名称,用于存储tls相关的文件
    :param ip: IP 地址或域名
    :return: 文件夹名称
    """

    random_number = ''.join(random.choices('0123456789', k=6))

    # 将 IP 或域名中的 . 替换为 -
    converted_ip = str(ip).replace(".", "-")

    # 将随机数添加到转换后的字符串中
    result = f"{converted_ip}-{random_number}"

    return result

swagger请求

 如下,在配置时,传入多个参数。

image-20240506141542082

 由于按照Form参数类型传入值,因此需要再代码中重新组织这些参数,完成序列化。

    db_host = DBHost(host_ip=fastbuild_host, host_port=fastbuild_port)
    db_harbor = DBHarbor(username=harbor_username, password=harbor_password, registry=harbor_registry, registry_dns=harbor_registry_dns)
    db_docker = DBDockerServer(host=docker_host, port=docker_port, tls_verify=False)

总结

 这主要是因为之前FastBuild系统的启动,需要依赖一个外部Docker服务器来进行系统镜像的构建,因此,在启动的时候,需要事先准备好TLS支持的配置文件"ca-jenkins.pem", “cert-jenkins.pem”, “key-jenkins.pem”,而这样优化之后,则可以先启动FastBuild,通过接口完成对于FastBuild的配置,从而减少FastBuild的依赖,这真的是很好的一种工程实践。

注: 我们应该尽量增强工程的可配置性,而减少依赖性。不然每次重新部署,都需要花费很多的时间,让人非常的痛苦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1654182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL查询语句(三)范围查找关键字

在上一篇文章中,我们介绍了SQL语句中,逻辑关键字的作用,并举例演示了如何用逻辑关键字来组合WHERE子句。在文章的末尾我们提到了两个用于范围查找的关键字IN和BETWEEN。这两个关键字都可以与NOT关键字灵活组合,起到对字句结果取反…

【算法】滑动窗口——将x减到0的最小操作数

本节博客主要是讲的我解“将x减到0的最小操作数”这道题的思路历程,从最开始的想法到代码提交的详细记录,有需要借鉴即可。 目录 1.题目2.代码示例3.细节3.1left越界3.2特殊情况 4.总结 1.题目 题目链接:LINK 看题目意思是就是给你一个数X&…

Redis(主从复制搭建)

文章目录 1.主从复制示意图2.搭建一主多从1.搭建规划三台机器(一主二从)2.将两台从Redis服务都按照同样的方式配置(可以理解为Redis初始化)1.安装Redis1.yum安装gcc2.查看gcc版本3.将redis6.2.6上传到/opt目录下4.进入/opt目录下然…

VueReal将在Display Week上推出microLED创新技术

公司展示将microLED从晶圆转移到背板的“改变游戏规则”的平台 在2024年显示周(5月12日至16日在圣何塞举行)上,VueReal将展示其MicroSolid打印平台,并展示其在推动微LED显示器和其他微型半导体器件在智能手机显示器和AR/VR解决方案…

Linux进程间通信:system V共享内存

目录 一、什么是共享内存 1.1创建共享内存 1.2释放共享内存 1.2.1shmctl 1.2.2shmat 1.2.3 shmdt 二、共享内存的实现及使用 2.1ShmClient 2.2Shm_Server 2.3Fifo.hpp 2.4Comm.hpp 一、什么是共享内存 标准系统V也叫system V的本地通信方式一般有三种: …

论文阅读】 ICCV-2021-3D Local Convolutional Neural Networks for Gait Recognition

motivation :现有方法方法无法准确定位身体部位,不同的身体部位可以出现在同一个条纹(如手臂和躯干),一个部分可以出现在不同帧(如手)的不同条纹上。其次,不同的身体部位具有不同的尺度,即使是不同帧中的同一部分也可以出现在不同…

2024041702-计算机操作系统 - 死锁

计算机操作系统 - 死锁 计算机操作系统 - 死锁 必要条件处理方法鸵鸟策略死锁检测与死锁恢复 1. 每种类型一个资源的死锁检测2. 每种类型多个资源的死锁检测3. 死锁恢复 死锁预防 1. 破坏互斥条件2. 破坏占有和等待条件3. 破坏不可抢占条件4. 破坏环路等待 死锁避免 1. 安全状态…

06-beanFactoryPostProcessor的执行

文章目录 invokeBeanFactoryPostProcessors(beanFactory)invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);invokeBeanFactoryPostProcessors(regularPostProc…

docker desktop实战部署oracle篇

1、前言 oracle数据库官方已提供现成的镜像,可以直接拿来部署了。 由于项目中需要使用oracle数据库的分表功能,之前安装的是standard版本,无奈只能重新安装。网上查了一番,使用的方法都比较传统老旧:下载安装包手动安…

Ps中 饱和度 和 自然饱和度 的区别?

1.饱和度(Saturation):在Photoshop中,饱和度是一个全局性调整,它影响图像中所有颜色的鲜艳程度。当你增加饱和度时,所有的颜色都会变得更浓烈、更鲜艳;相反,减小饱和度会使图像整体变…

解决 git克隆拉取代码报SSL certificate problem错误

问题:拉取代码时报错,SSL证书问题:证书链中的自签名证书问题 解决:只需要关闭证书验证,执行下面代码即可: git config --global http.sslVerify "false" 再次拉取代码就可以了

怎样选择IT外包公司?需要注意什么?

随着网络化、数字化、智能化快速发展,一部分企业成立自己的IT部门,负责各个科室的网络安全,大部分企业把网络安全、数据安全,外包给专业的IT外包公司,既提升了办公效率,企业又能把主要精力放在发展核心业务…

(二刷)代码随想录第1天|704. 二分查找 27. 移除元素

704. 二分查找 704. 二分查找 - 力扣(LeetCode) 代码随想录 (programmercarl.com) 手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili 给定一个 n 个元素有序的(升序&#xff09…

Unity如何使用adb工具安装APK

1、下载adb工具 SDK 平台工具版本说明 | Android Studio | Android Developers (google.cn) 2、配置环境变量 把platform-tools的路径添加进去就行 打开cmd,输入adb,即可查看版本信息 3、使用数据线连接设备,查看设备信息(…

后教培时代的新东方,正在找寻更大的教育驱动力?

近段时间,K12教育主要上市公司的阶段性业绩皆已出炉。从具体数据来看,随着时间推移,教培机构的转型之路已愈走愈顺。 财报显示,2023年12月1日-2024年2月29日,好未来实现营收4.3亿美元,同比增长59.7%&#…

C++ | Leetcode C++题解之第60题排列序列

题目&#xff1a; 题解&#xff1a; class Solution { public:string getPermutation(int n, int k) {vector<int> factorial(n);factorial[0] 1;for (int i 1; i < n; i) {factorial[i] factorial[i - 1] * i;}--k;string ans;vector<int> valid(n 1, 1);…

小程序支付的款项流转与到账时间

商家做小程序&#xff0c;最关心的是客户通过小程序下单支付的钱&#xff0c;是怎么样的流转状态以及最终到哪里。因此&#xff0c;本文将详细解析款项最终流向何处以及多久能够到账。 一、小程序支付的款项流向 当用户在小程序内完成支付后&#xff0c;款项并不会直接到达商…

数据结构学习——线性表、顺序表

1.线性表 线性表 &#xff08; linear list &#xff09; 是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一…

多线程【阻塞队列】(生产者消费者模型代码实现)

阻塞队列 解耦合削峰填谷生产者消费者模型&#xff1a; 解耦合 削峰填谷 生产者消费者模型&#xff1a; 正常来说&#xff0c;wait通过notify唤醒&#xff0c;其他线程调用了take,在take的最后一步进行notify. package thread; class MyBlockingQueue{private String [] data…

jmeter控制器讲解

1&#xff0c;随机顺序控制器和随机控制器的区别&#xff1a;随机顺序控制器下所有的接口都会执行&#xff0c;只是执行顺序是随机的&#xff0c;随机控制器下所有的接口中随机执行一个接口&#xff0c;其余接口不执行。