Direct user upload to GCS with given name and parameters

纵饮孤独 提交于 2019-12-18 09:34:52

问题


I want to enable clients of my Python GAE app to upload files directly to GCS using a specific object name and GCS parameters I set up front (such as cache control and ACL), and perform some actions after the upload has finished.

I currently use the blobstore.create_upload_url for this. However, since I cannot give any parameters or object name up front, I need to copy the entire file to a new location on GCS from within the 'uploaded' callback handler. This is time and (compute) resource consuming, and sounds like it could be avoided.

Is there any way to optimize this process?

  • Can I create an upload URL that will immediately upload an object with the right name and right ACL + Cache control parameters? (I briefly looked at signed URLs, but those don't seem to support a callback handler like the blobstore API does)
  • If not, is there a way to not have to copy the file byte by byte to the new location and delete it when i'm done? (being able to move a file and change its attributes would be nice)

Update: I just noticed the GCS python client library has copy2 now. I could have sworn this wasn't there before, but it sounds like it answers the second question.


回答1:


Here is my Python, webapp2, jinja code for a direct upload (post) to GCS using a signed form with a policy document:

def gcs_upload(acl='bucket-owner-read'):
    """ jinja2 upload form context """

    default_bucket = app_identity.get_default_gcs_bucket_name()
    google_access_id = app_identity.get_service_account_name()
    succes_redirect = webapp2.uri_for('_gcs_upload_ok', _full=True)
    expiration_dt = datetime.now() + timedelta(seconds=300)

    policy_string = """
    {"expiration": "%s",
              "conditions": [
                  ["starts-with", "$key", ""],
                  {"acl": "%s"},
                  {"success_action_redirect": "%s"},
                  {"success_action_status": "201"},
              ]}""" % (expiration_dt.replace(microsecond=0).isoformat() + 'Z', acl, succes_redirect)

    policy = base64.b64encode(policy_string)
    _, signature_bytes = app_identity.sign_blob(policy)
    signature = base64.b64encode(signature_bytes)

    return dict(form_bucket=default_bucket, form_access_id=google_access_id, form_policy=policy, form_signature=signature,
            form_succes_redirect=succes_redirect, form_acl=acl)


class GcsUpload(BaseHandler):

    def get(self):

        self.render_template('gcs_upload.html', **gcs_upload())

And the form fields:

<form method="post" action="https://storage.googleapis.com/{{ form_bucket }}" enctype="multipart/form-data">
    <input type="hidden" id="key" name="key" value="images/test.png">
    <input type="hidden" name="GoogleAccessId" value="{{ form_access_id }}">
    <input type="hidden" name="acl" value="{{ form_acl }}">
    <input type="hidden" name="success_action_redirect" value="{{ form_succes_redirect }}">
    <input type="hidden" name="success_action_status" value="201">
    <input type="hidden" name="policy" value="{{ form_policy }}">
    <input type="hidden" name="signature" value="{{ form_signature }}">
    <input name="file" type="file">
    <input type="submit" value="Upload">
</form>

Docs GCS upload using a form here



来源:https://stackoverflow.com/questions/31452720/direct-user-upload-to-gcs-with-given-name-and-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!