使用S3预签名URL上传APK到Device Farm后找不到文件问题
错误原因
- 上传请求格式错误:你调用
requests.put时使用了files参数,该参数会自动将请求格式转为multipart/form-data,而AWS Device Farm的预签名上传URL要求请求体直接为APK文件的二进制内容,和你用curl -T的行为一致。预签名URL对应的是S3存储接口,只要内容成功传到S3就会返回200,但后续Device Farm异步校验文件时,会因为内容格式不符合APK要求判定为无效,因此不会在控制台展示该文件。 - 逻辑顺序错误:你当前代码在拿到预签名URL后先休眠10秒、查询上传状态,再执行上传操作,顺序完全颠倒。正确的流程应该是拿到预签名URL后立即上传文件,之后再查询上传处理状态。
- 请求头命名不规范:你定义的请求头键为
contentType,标准HTTP请求头应该为Content-Type,部分场景下会导致服务端识别异常。 - 文件路径硬编码风险:代码中打开的文件是固定写死的
app-release-04.apk,没有使用入参的file_name,如果入参文件名和实际文件不一致也会导致上传错误。
修正后的代码
import boto3 import requests import time CLIENT = boto3.client("devicefarm", region_name="us-west-2") def create_upload(project_arn, file_name, type): response = CLIENT.create_upload( projectArn=project_arn, name=file_name, type=type, contentType="application/octet-stream" ) try: app_arn = response["upload"]["arn"] signed_url = response["upload"]["url"] # 直接读取文件二进制内容作为请求体,对应curl -T的行为 with open(file_name, "rb") as f: file_content = f.read() headers = { "Content-Type": "application/octet-stream" } # 不用files参数,直接传data为二进制内容 api_response = requests.put(url=signed_url, data=file_content, headers=headers) api_response.raise_for_status() # 主动抛出HTTP错误,方便排查 # 上传完成后再轮询查询上传处理状态 while True: status_resp = CLIENT.get_upload(arn=app_arn) upload_status = status_resp["upload"]["status"] print(f"当前上传处理状态:{upload_status}") if upload_status in ["SUCCEEDED", "FAILED"]: break time.sleep(2) if upload_status == "FAILED": raise Exception(f"上传处理失败,错误信息:{status_resp['upload'].get('message', '无明确错误信息')}") except KeyError: raise KeyError(f"创建上传任务失败! 入参:project_arn: {project_arn}, file_name: {file_name}, type: {type},返回内容:{response}") return app_arn
内容的提问来源于stack exchange,提问作者Frankster
相关产品推荐
相关产品推荐

