微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用签名网址上传到 Python 中的 Google Storage 存储分区?

如何解决如何使用签名网址上传到 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 = ma​​in...”删除了下面的代码片段)。


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 举报,一经查实,本站将立刻删除。