如何解决如何使用签名网址上传到 Python 中的 Google Storage 存储分区?
我能够创建签名 URL,只需要知道在创建后如何处理它们。
有几个使用 Javascript 通过签名 URL 上传的示例,但我在 Python 中找不到任何示例。我正在尝试使用签名网址来解决 Google App Engine 对我的 Flask 应用程序施加的 32 MB 限制。
这是我的 python app.py 脚本(这里不是我的应用程序的全部功能,只是尝试成功上传到我的存储桶):
from flask import Flask,request,render_template
from google.cloud import storage
import pandas as pd
import os
import gcsfs
bucket_name = "my-bucket"
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '/path/to/file.json'
app = Flask(__name__)
def upload_blob(bucket_name,source_file_name,destination_blob_name):
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(destination_blob_name)
blob.upload_from_file(source_file_name)
print("success")
@app.route('/')
def homepage():
return render_template('home.html')
@app.route('/',methods = ['GET','POST'])
def upload_file():
if request.method == 'POST':
file1 = request.files['file1']
file2 = request.files['file2']
upload_blob(bucket_name,file1,'file-1')
upload_blob(bucket_name,file2,'file-2')
df = pd.read_csv('gs://' + bucket_name + '/' + 'file-1')
print(df.shape)
return "done"
if __name__ == "__main__":
app.run(debug=True)
这是我用来创建签名 URL 的函数:
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')
下面是我的 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>
根据我在这里研究的内容,我尝试上传到的存储桶的 CORS 配置:
[
{"maxAgeSeconds": 3600,"method": ["GET","PUT","POST"],"origin": ["https://my-app.uc.r.appspot.com","http://local.machine.XXXX/"],"responseHeader": ["Content-Type"]}
]
生成的签名 URL 是否包含在 html 表单中?需要进入我的upload_file函数吗?
最后,当我将签名的 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 上构建一个网络应用程序,需要签名 URL 来解决 32 MB 文件上传限制。
更新
在意识到我只需要向签名 URL 发出请求后,我就找到了签名 URL 组件。
下面是我在 App Engine 中加载的新脚本(导入和“if name = main...”删除了下面的代码片段)。
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('/','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,FILE_TYPE)
df_diag = pd.read_csv('gs://' + BUCKET + '/' + 'diag.csv')
print(df_diag.shape)
return "done"
上面的代码还是抛出413 entity too large错误。我认为这是因为即使我正在创建签名 URL,我也已经通过 App Engine 进行了“POST”。我需要如何重新安排/我做错了什么?需要如何构造代码才能让用户通过签名网址直接上传到 Google Cloud Storage 并避免触发 413 entity too large 错误?
解决方法
在服务器上生成签名 URL 后,您只需要将其发送回客户端并使用它来上传您的文件。例如,您可以使用普通的 fetch put 请求发送文件数据,或者我更喜欢始终使用 axios:
await axios.put(url,file);
这里的 url 是签名的 url。您可能希望将文件作为 formData
发送版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。