最近开发了一个进行源码展示的小程序。每次新增一个项目信息都会展示项目效果的演示图。因此在新增数据之前,需要把演示图先上传到云存储。基于此通过python实现文件的上传。
1、获取access_token
2、文件上传api
文件上传的api需要分两步调用。
第一次请求"获取上传链接"接口https://api.weixin.qq.com/tcb/uploadfile?access_token=ACCESS_TOKEN
,post参数为云开发环境id env以及云存储的目标路径path。从该接口的返回值中得到上传url以及相关的上传密钥,再进行文件流的上传。
2.1 获取上传/下载链接
class Cloud:
def __init__(self, env, collection_name):
self.access_token = get_access_token()
self.add_url = f'https://api.weixin.qq.com/tcb/databaseadd?access_token={
self.access_token}'
self.upload_url = f'https://api.weixin.qq.com/tcb/uploadfile?access_token={
self.access_token}'
self.download_url = f'https://api.weixin.qq.com/tcb/batchdownloadfile?access_token={
self.access_token}'
self.env = env
self.collection_name = collection_name
self.post_data = {
"env": self.env} # 请求参数,每次的请求参数需要env环境id和query查询语句
def upload(self, file_name):
post_data = {
"env": self.env, "path": file_name}
res = requests.post(self.upload_url, data=json.dumps(post_data))
return res.json()
def download(self, file_id, max_age=7200):
post_data = {
"env": self.env, "file_list": [{
"fileid": file_id, "max_age": max_age}]}
res = requests.post(self.download_url, data=json.dumps(post_data))
return res.json()
def add(self, new_data):
"""
new_data: list of dict
"""
new_data = "{data:%s}" % new_data
self.post_data["query"] = f"db.collection('{
self.collection_name}').add({
new_data})"
response = requests.post(self.add_url, data=json.dumps(self.post_data))
result = response.json()
# 执行成功返回状态码0
if result["errcode"] == 0:
return result['id_list']
2.2根据上传参数的返回值进行文件流上传
这里我们看下拿到上传链接后的返回是怎样的。这里官方文档给出了具体数据规范
需要注意的是上传的请求格式为multipart/form-data。一个上传文件的完整流程可以通过如下函数实现。
在获取上传链接后,将该链接代入到下载链接中,获取返回值,判断文件不存在时再上传,否则中断上传操作。
def upload_file(img_path, env, collection_name):
"""
img_path:本地图片/文件路径
"""
cloud = Cloud(env, collection_name)
# 需要上传的云存储文件夹名称
cloud_dir_name = "."
# 第一次请求获取上传连接
upload_path = f"{
cloud_dir_name}/{
img_path}"
res = cloud.upload(upload_path)
file_id = res['file_id']
# 从上传链接中获取file_id检查该文件是否存在
check_exisit = cloud.download(file_id)
# 调用下载链接确认文件不存在再上传
if check_exisit["errcode"] == 0 and check_exisit["file_list"][0]["status"] == 1:
# 拿到上传连接后获取密钥,读取本地文件流上传
if res["errcode"] == 0:
post_data = {
"key": upload_path,
"Signature": res["authorization"],
"x-cos-security-token": res["token"],
"x-cos-meta-fileid": res["cos_file_id"],
"file": open(img_path, "rb")
}
url = res["url"]
body = MultipartEncoder(
fields=post_data,
boundary=''.join(random.sample(string.ascii_letters + string.digits, 30))
)
headers = {
"Content-Type": body.content_type}
upload_res = requests.post(url, data=body, headers=headers)
if upload_res.status_code!=204:
print(upload_res.content)
import sys
sys.exit(0)
else:
print(f"{
cloud_dir_name}文件已存在,直接读取")
# 文件上传完成后加入数据库
item["img_path"] = file_id
res = cloud.add(item)
print(res)
最终界面数据的展示效果可以通过小程序查看