大家好~我是米洛

我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程,希望大家多多支持。

欢迎关注我的公众号米洛的测开日记,获取最新文章教程!

回顾

上一节我们编写了在线执行测试计划功能,并稍微改了下报告页面。那其实我们之前的内容都是有很多在里面的。

比如http请求只支持了json和form,没有支持文件上传的请求,甚至有一些crud的功能都没有太完善。

不过不要紧,我的想法还是先创造,再完善。当然也不是盲目创造,也得提前预判好后面的走向。

为什么要用oss

pity里面oss打算用在2个地方,第一个就是一些静态资源图片。比方说项目图片用户头像

另一个地方就是上文说的,测试文件上传接口的时候,我们需要测试文件。这些文件怎么来,怎么管理?都得借助oss来完成。

目前以我熟悉的oss为例,打算支持以下几种oss:

  • 阿里云oss

  • 腾讯云cos ~~腾讯云cos~~(无账号)

  • 七牛云(免费,我能给展示demo)

  • gitee(免费)

    其中阿里云和腾讯云由于都是付费产品,博主还是买不起的。所以可能需要有对应的测试账号,在此感谢小右(Mini-Right)的帮助,给了我一个阿里云的测试账号,保证了crud能正常进行。

    如果需要我实现其他oss客户端,请带上对应的测试账号私信我哈。

    测试网站的数据估计会用gitee或者七牛云

说明

关于文件管理这块,由于时间关系,我暂时不会落一张表与oss数据进行关联,主要目的是为了节省时间

表关联可以作为二期工程。

编写oss基类

新建app.middleware.oss.oss_file.py

由于咱们支持多种oss客户端,所以包装好一个抽象类(类似go的interface)等着各个oss客户端去实现之。

from abc import ABC, abstractmethod
from typing import ByteString class OssFile(ABC): @abstractmethod
def create_file(self, filepath: str, content: ByteString):
pass @abstractmethod
def update_file(self, filepath: str, content: ByteString):
pass @abstractmethod
def delete_file(self, filepath: str):
pass @abstractmethod
def list_file(self):
pass @abstractmethod
def download_file(self, filepath):
pass

抽象类没有具体的实现,只有方法的定义,目的是为了限制子类的方法,即必须实现基类中定义的方法。

总结了一下,必须有增删改查下载5种方法。

编写AliyunOss实现

新建app.middleware.oss.aliyun.py

from typing import ByteString

import oss2

from app.middleware.oss.files import OssFile

class AliyunOss(OssFile):

    def __init__(self, access_key_id: str, access_key_secret: str, endpoint: str, bucket: str):
auth = oss2.Auth(access_key_id=access_key_id,
access_key_secret=access_key_secret)
# auth = oss2.AnonymousAuth()
self.bucket = oss2.Bucket(auth, endpoint, bucket) def create_file(self, filepath: str, content: ByteString):
self.bucket.put_object(filepath, content) def update_file(self, filepath: str, content: ByteString):
self.bucket.put_object(filepath, content) def delete_file(self, filepath: str):
self.bucket.delete_object(filepath) def list_file(self):
ans = []
for obj in oss2.ObjectIteratorV2(self.bucket):
ans.append(dict(key=obj.key, last_modified=obj.last_modified,
size=obj.size, owner=obj.owner))
return ans def download_file(self, filepath):
if not self.bucket.object_exists(filepath):
raise Exception(f"oss文件: {filepath}不存在")
return self.bucket.get_object(filepath)

AliyunOss继承了OssFile,构造方法获取阿里云的身份信息,并验证。最后读取bucket,这bucket我理解的是一块区域,你的文件都存储在这块区域里面,我们就叫他F盘吧。

其他的方法很简单,基本上是调用对应的api,去做crud操作。oss没有文件夹的概念,都是统一用路径来存储文件地址的,比如:

woody/github.txt

这个文件路径可以理解为,woody目录下的github.txt文件。

编写获取客户端方法

app.middleware.oss._\_init__.py

from app.core.configuration import SystemConfiguration
from app.middleware.oss.aliyun import AliyunOss
from app.middleware.oss.files import OssFile class OssClient(object):
_client = None @classmethod
def get_oss_client(cls) -> OssFile:
"""
通过oss配置拿到oss客户端
:return:
"""
if OssClient._client is None:
cfg = SystemConfiguration.get_config()
oss_config = cfg.get("oss")
access_key_id = oss_config.get("access_key_id")
access_key_secret = oss_config.get("access_key_secret")
bucket = oss_config.get("bucket")
endpoint = oss_config.get("endpoint")
if oss_config is None:
raise Exception("服务器未配置oss信息, 请在configuration.json中添加")
if oss_config.get("type").lower() == "aliyun":
return AliyunOss(access_key_id, access_key_secret, endpoint, bucket)
raise Exception("不支持的oss类型")
return OssClient._client

我们在configuration.json配置oss信息,接着每次都从OssClient获取客户端即可。

编写后端接口

from fastapi import APIRouter, File, UploadFile

from app.handler.fatcory import PityResponse
from app.middleware.oss import OssClient router = APIRouter(prefix="/oss") @router.post("/upload")
async def create_oss_file(filepath: str, file: UploadFile = File(...)):
try:
file_content = await file.read()
# 获取oss客户端
client = OssClient.get_oss_client()
client.create_file(filepath, file_content)
return PityResponse.success()
except Exception as e:
return PityResponse.failed(f"上传失败: {e}") @router.get("/list")
async def list_oss_file():
try:
client = OssClient.get_oss_client()
files = client.list_file()
return PityResponse.success(files)
except Exception as e:
return PityResponse.failed(f"获取失败: {e}") @router.get("/delete")
async def delete_oss_file(filepath: str):
try:
client = OssClient.get_oss_client()
client.delete_file(filepath)
return PityResponse.success()
except Exception as e:
return PityResponse.failed(f"删除失败: {e}") @router.post("/update")
async def update_oss_file(filepath: str, file: UploadFile = File(...)):
"""
更新oss文件,路径不能变化
:param filepath:
:param file:
:return:
"""
try:
client = OssClient.get_oss_client()
file_content = await file.read()
client.update_file(filepath, file_content)
return PityResponse.success()
except Exception as e:
return PityResponse.failed(f"删除失败: {e}")

方法很简单,文件路径在url参数里边,文件的话,利用fastapi里面的File和UploadFile皆可获取到上传的文件。

注意,必须先安装python-multipart库配合文件上传

测试一下

成功读取到了oss的文件信息,但下载接口

好像忘记下载文件相关内容了,那么参考我的上一篇FsatApi下载文件的文章吧。

FastApi下载文件

或者直接去github查看源码~

今天的内容就介绍到这里了,下一节卷oss的用途。

最新文章

  1. 简约的ASP.NET 系统框架,提供源码。
  2. Linux下Chrome浏览器不支持WebGL的解决方式。
  3. 使用C++/C qsort 标准库对结构体进行快速排序
  4. Delphi - GetUserNameEx(学一下导出Windows API,以及Array Char充当缓冲区的用法,下标必须从零开始)
  5. Codeforces Round #386 (Div. 2)
  6. 第一百一十节,JavaScript匿名函数和闭包
  7. java.util.ArrayList、java.util.vector和java.util.LinkedList (JDK 1.8.0_111)
  8. Linux学习--进程概念
  9. Java之文本文件的创建和读取(含IO流操作)
  10. 从web到搭建ssm环境
  11. postman变量的使用和设置
  12. JDK7与8内存参数解析与修改
  13. 【问题解决:连接异常】 java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long
  14. 方法(method)和函数(function)的区别
  15. 大数据入门第二十天——scala入门(二)scala基础01
  16. thinkphp---部署在IIS8.0服务器上
  17. gitlab安装教程、gitlab官网、英文文档
  18. pt1000测温度
  19. Hibernate关系映射 一对一双向外键关联@OneToOne Annotation方式 双向关联和单向关联的区别
  20. Unity3D协程介绍 以及 使用

热门文章

  1. Sweetalert模态对话框与Swiper轮播插件、Bootstrap样式组件、AdminLTE后台管理模板地址
  2. List去重复
  3. 隐式参数arguments
  4. go 把固定长度的数字写入字节切片 (byte slice),然后从字节切片中读取到并赋值给一个变量:
  5. git rm 与 git rm --cached 的区别
  6. 抽签小程序(C语言随机数)
  7. 深入了解Element Form表单动态验证问题 转载
  8. java篇之JDBC原理和使用方法
  9. 一个label 混搭不同颜色,不同字体的文字.. by 徐
  10. K8s二进制部署单节点 etcd集群,flannel网络配置 ——锥刺股