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

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的依赖,这真的是很好的一种工程实践。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

应急响应靶机训练-近源渗透OS-1

前言 应急响应靶机训练,为保证每位安服仔都有上手的机会,不做理论学家,增加动手经验,可前来挑战应急响应靶机-近源渗透OS1,此系列后期会长期更新,关注本公众号,被动学习。 挑战内容 前景需要:…

Spring Gateway的核心功能:路由、过滤、限流一网打尽

Spring Gateway的简介 在微服务架构的世界里,如同繁星点点的服务需要一个指挥家,将它们有序地组织起来,让它们能够和谐地协同工作。这个指挥家,就是Spring Gateway。它是一个基于Spring Framework 5、Project Reactor和Spring Bo…

Java多线程:常见的线程的创建方法及Thread类详解

目录 一.并发编程相关概念 线程与进程 多线程 Java中线程的状态 二.线程的创建方法 方法一:继承Thread类 方法二:实现Runnable接口 其他方法 三.Thread类详解 Thread常见构造方法 Thread常见属性 Thread常见方法 start() 与 run() sleep(…

使用代理IP时,如何预防未知的风险?

在使用代理IP时,预防未知的风险是至关重要的。代理IP虽然提供了诸多便利,如匿名浏览、访问控制和内容过滤等,但如果不加以妥善管理和使用,可能会面临数据泄露、隐私暴露、恶意活动关联等风险。以下是一些建议,以帮助您…

Java中的maven的安装和配置

maven的作用 依赖管理 方便快捷的管理项目依赖的资源,避免版本冲突问题 统一项目管理 提供标准,统一的项目结构 项目构建 标准跨平台(Linux、windows、MacOS)的自动化项目构建方式 maven的安装和配置 在maven官网下载maven Ma…

如何用Kimi,5秒1步生成流程图

引言 在当前快节奏的工作环境中,拥有快速、专业且高效的工具不可或缺。 Kimi不仅能在5秒内生成专业的流程图(kimi),还允许实时编辑和预览,大幅简化了传统流程图的制作过程。 这种迅速的生成能力和高度的可定制性使得…

如何使用低代码快速创建一个复杂交叉报表?

前言 在当今数字化时代,数据是企业决策和发展的重要支柱。为了更好地理解和利用数据,生成清晰、全面的报表至关重要。而复杂交叉报表作为一种高级数据分析工具,能够帮助企业深入挖掘数据背后的价值,提供全面的数据概览和分析结果…

数据分析——业务指标量化

业务指标量化 前言一、统计指标二、统计指标特点完整的统计指标统计指标的理解和使用方法 三、统计指标类型总量指标时期指标时点指标总量指标的作用 相对指标计划完成相对数指标结构相对数指标比例相对数指标比较相对数指标动态相对数指标 平均指标 四、数量指标和质量指标五、…

Java设计模式 _结构型模式_代理模式(静态,动态)

一、基础概念 1、代理模式 代理模式(Proxy Pattern)是一种结构型设计模式。它允许我们通过添加一个代理对象来控制对另一个对象的访问,从而实现一些额外的功能,如访问控制、日志记录、性能监控等。代理模式主要分为静态代理和动态…

Versatile Diffusion—— 融合文本和图像的扩散模型

介绍 Diffusion模型在各种生成任务中取得了显著的进展,成为了一个重要的里程碑。特别是像DALLE 2、Imagen和Stable Diffusion(SD)这样的模型,不仅在学术界引起了广泛关注,也在工业界产生了深远影响。尽管这些模型在特…

10.Java对象内置结构

文章目录 Java对象内置结构1.Java对象的三个部分1.1.对象头1.2.对象体1.3.对齐字节 2.对象结构中核心字段的作用2.1.MarkWord(标记字)2.2.Class Pointer(类对象指针)2.3.Array Length(数组长度)2.4.对象体2.5.对齐字节 3.Mark Word的结构信息3.1.不同锁状态下的Mark Word字段结…

K邻算法:在风险传导中的创新应用与实践价值

程序员的实用神器 ⛳️ 写在前面参与规则!!! ✅参与方式:关注博主、点赞、收藏、评论,任意评论(每人最多评论三次) ⛳️本次送书1~4本【取决于阅读量,阅读量越多,送的越…

Ubuntu24.04安装中文输入法

Ubuntu24.04安装中文输入法 为了更好的体验,请访问个人博客 www.huerpu.cc:7000 一、添加中文语言支持 在安装中文输入法之前,首选要添加中文语言支持。选择System,点击Region & Language。 点击Manage Install Languages。 点击Insta…

LED显示屏的维护与使用指南

LED显示屏作为一种先进的显示技术,广泛应用于广告、信息显示、舞台背景等领域。然而,为了确保显示屏的长期稳定运行和良好的显示效果,对其进行正确的维护和使用是非常必要的。以下是一些专业的维护与使用建议: 维护建议&#xff1…

Android iw 工具

代码位置:Android/external/iw 查看支持的命令: console:/ # iw help Usage: iw [options] command Options:--debug enable netlink debugging--version show version (4.1) Commands:help [command]Print usage for all or a specific command, e.g."…

六西格玛管理培训公司挑选攻略:如何找到最适合你的合作伙伴?

面对众多提供六西格玛管理培训的公司,企业如何挑选到真正适合自己的呢?本文有建议如下: 一、明确培训目标 在选择六西格玛管理培训公司之前,企业首先要明确自身的培训需求和目标。这包括确定培训的范围、期望达到的效果以及预算…

docker-compose完成mysql8.0+环境搭建

1、准备my.cnf文件到指定目录(和基础的增加了一个default_authentication_pluginmysql_native_password 的身份验证插件配置信息) 原因:官方提到: 该方式可以解决:Authentication plugin ‘caching_ sha2_password‘ c…

【代码分享】使用HTML5的Canvas绘制编码说明图片

最急在工作中遇到一个需求,根据给定的编码生成编码说明,像下面这样的效果。 不同含义的编码用横杠分割,然后每个编码下面用箭头指明具体的含义。下面是我使用canvas实现的代码。具体的编码宽度大家可以根据实际情况进行调整,目前…

炒股沪指放量涨逾1%,医药、酿酒等板块强势

5月首个交易日,两市股指高开高走,盘中大幅单边上行,两市成交额连续4个交易日突破万亿元,北向资金大举进场扫货,一度净买入超100亿元。 同创优配是AAA 级诚信经营示范单位,中国人民银行备案认证,天眼查可查询。是一家专注于股票投资、金融服务、及资产管理的专业机构 截至收盘…

代码随想录算法训练营第36期DAY14

DAY14(周二) 二叉树的递归遍历 144二叉树的前序遍历 过了。 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullp…