在Python中如何使用签名URL上传到Google存储桶?
我能够创建签名的URL,只需要知道创建后如何处理它们 有几个例子使用Javascript通过签名URL上传,但我在Python中找不到任何例子。我正在尝试使用签名URL作为解决Google App Engine对我的Flask应用程序施加的32 MB限制的方法 这是我的python app.py脚本(这里不是我应用程序的全部功能,只是尝试成功上传到我的bucket): 下面是我用来创建签名URL的函数:在Python中如何使用签名URL上传到Google存储桶?,python,google-app-engine,flask,google-cloud-storage,signed-url,Python,Google App Engine,Flask,Google Cloud Storage,Signed Url,我能够创建签名的URL,只需要知道创建后如何处理它们 有几个例子使用Javascript通过签名URL上传,但我在Python中找不到任何例子。我正在尝试使用签名URL作为解决Google App Engine对我的Flask应用程序施加的32 MB限制的方法 这是我的python app.py脚本(这里不是我应用程序的全部功能,只是尝试成功上传到我的bucket): 下面是我用来创建签名URL的函数: def generate_upload_signed_url_v4(bucket_name,
def generate_upload_signed_url_v4(bucket_name, blob_name):
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(blob_name)
url = blob.generate_signed_url(
version="v4",
# This URL is valid for 15 minutes
expiration=datetime.timedelta(minutes=15),
# Allow GET requests using this URL.
method="PUT",
content_type="application/octet-stream",
)
print(url)
return url
generate_upload_signed_url_v4(bucket_name, 'file.csv')
下面是my home.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test upload</title>
</head>
<body>
<h3> test upload </h3>
<form method="POST" action="/" enctype="multipart/form-data">
<p>Upload file1 below</p>
<input type="file" name="file1">
<br>
<br>
<p>Upload file2 below</p>
<input type="file" name="file2">
<br>
<br>
<input type="submit" value="upload">
</form>
</body>
</html>
生成的签名URL是否以html形式存在?是否需要进入我的上传文件功能
最后,当我将已签名的URL粘贴到浏览器中时,会显示以下错误:
<Error>
<Code>MalformedSecurityHeader</Code>
<Message>Your request has a malformed header.</Message>
<ParameterName>content-type</ParameterName>
<Details>Header was included in signedheaders, but not in the request.</Details>
</Error>
这是我的第一个SO问题,所以如果它结构不好,我很抱歉。我是超级迷茫,是新来的GCP。我已经搜索了一段时间了,但没有找到Python/Flask的用例,在这个用例中,我可以看到签名URL是如何合并到文件上传过程中的
同样,我正在Google App Engine flex上构建一个webapp,需要有签名的URL来绕过32MB的文件上传限制
更新
在意识到我只需要对签名的URL发出请求后,我找到了签名的URL组件
下面是我在App Engine中加载的新脚本(为下面的代码段导入并删除“ifname=main..”
上面的代码仍然抛出413实体太大的错误。我想这是因为即使我正在创建签名的URL,我的“帖子”也会通过应用程序引擎进行。我需要如何重新安排/我做错了什么?代码需要如何构造才能让用户通过签名url直接上传到Google云存储,避免触发413实体过大错误?一旦在服务器上生成签名url,您只需将其发送回客户端并使用它上传文件。例如,您可以使用普通的fetch put请求发送文件数据,或者我更喜欢使用axios:
await axios.put(url, file);
此处的url是已签名的url。您可能希望将文件作为发送。您可以尝试两种方法吗:1。生成签名url时使用路径作为blob
generate\u upload\u signed\u url\u v4(bucket\u name,“/upload/”)
。第二,你能把url方法从PUT改为POST吗?如果其中一个或两个解决了您的问题,请告诉我。在发现我只需向我创建的签名URL发出请求后,我确实实现了这一点。然而,它只在我的本地机器上工作,并且仍然在AppEngine上出现413错误,因为我测试的文件大于32MB。根据我所读到的,签名的URL应该直接上传到Google云存储,然后在上传之后,它们通过应用程序引擎触发应用程序逻辑。然而,我不知道这是如何做到的。当我尝试时,我仍然通过应用程序引擎发出POST请求,从而触发413错误。我做错了什么?你不必通过应用程序引擎。您的前端(用户浏览器)请求一个已签名的URL,您的后端生成该URL并将其发送到前端。然后浏览器使用签名的URL将文件上载到云存储。您还可以想象,在上传结束时,如果您需要跟踪后端中的文件,从前端到后端的一个调用将提供上传的文件(名称和位置)。这很有意义。我将如何实现让浏览器请求已签名的URL以从访问我的应用程序的用户上传文件?用户选择要上载的文件并通过应用程序单击“提交”是否会触发此事件?实现这一点的代码需要在“home.html”中还是在“app.py”中?我用新代码更新了我上面的问题,我使用新代码通过app Engine部署应用程序,这样你就可以看到我在哪里/我做错了什么。非常感谢您在这方面的帮助,我想我很快就能弄明白。不,您的代码需要将文件发送到App Engine。签名的url在这里是无用的。浏览器需要直接将文件发送到存储器,而无需应用程序引擎中介。我会试着做一些原型来展示给你们看,但我在frontend/javascript方面非常糟糕!您好,谢谢您的帮助,但我不熟悉异步函数。在得到一个“未等待”的错误后,我做了一些研究。我当时无法安装axios,目前仍在排除故障。与此同时,我能够通过一个简单的requests.put来使用url,类似于axios.put方法,但是我仍然通过Google应用程序引擎得到413错误。
<Error>
<Code>MalformedSecurityHeader</Code>
<Message>Your request has a malformed header.</Message>
<ParameterName>content-type</ParameterName>
<Details>Header was included in signedheaders, but not in the request.</Details>
</Error>
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '/path/to/file.json'
EXPIRATION = datetime.timedelta(minutes=15)
FILE_TYPE = 'text/csv'
BUCKET = 'my-bucket'
def upload_via_signed(bucket_name, blob_name, filename, expiration, file_type):
bucket = storage.Client().get_bucket(bucket_name)
blob = bucket.blob(blob_name)
signed_url = blob.generate_signed_url(method='PUT', expiration=expiration, content_type=file_type)
requests.put(signed_url, open(filename.filename, 'rb'), headers={'Content-Type': file_type})
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = '/tmp'
@app.route('/')
def homepage():
return render_template('home.html')
@app.route('/', methods = ['GET', 'POST'])
def upload_file():
if request.method == 'POST':
diag = request.files['file']
filename_1 = secure_filename(diag.filename)
filepath_1 = os.path.join(app.config['UPLOAD_FOLDER'], filename_1)
diag.save(filepath_1)
person = request.files['person']
filename_2 = secure_filename(person.filename)
filepath_2 = os.path.join(app.config['UPLOAD_FOLDER'], filename_2)
person.save(filepath_2)
upload_via_signed(BUCKET, 'diag.csv', diag, EXPIRATION, FILE_TYPE)
upload_via_signed(BUCKET, 'person.csv', person, EXPIRATION, FILE_TYPE)
df_diag = pd.read_csv('gs://' + BUCKET + '/' + 'diag.csv')
print(df_diag.shape)
return "done"
await axios.put(url, file);