表单上传是指使用OSS API中的PostObject请求来完成Object的上传,上传的Object不能超过5GB。

说明 表单上传的API接口详细信息请参见 PostObject

适用场景

表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例:

不使用表单上传 表单上传
流程对比
  1. 网站用户上传简历。
  2. 网站服务器回应上传页面。
  3. 简历被上传到网站服务器。
  4. 网站服务器再将简历上传到OSS。
  1. 网站用户上传简历。
  2. 网站服务器回应上传页面。
  3. 简历上传到OSS。
  • 从流程上来说,使用表单上传,少了一步转发流程,更加方便。
  • 从架构上来说,原来的上传都统一走网站服务器,上传量过大时,需要扩容网站服务器。采用表单上传后,直接从客户端上传数据到OSS,上传量过大时,压力都在OSS上,由OSS来保障服务质量。

SDK demo

请参见Java SDK

注意事项

  • 上传的Object的大小不能超过5GB。
  • 文件的命名规则如下:
    • 使用UTF-8编码。
    • 长度必须在1–1023字节之间。
    • 不能以正斜线(/)或者反斜线(\)字符开头。
  • 如果您在上传大量文件时,在命名上使用了顺序前缀(如时间戳或字母顺序),可能会出现大量文件索引集中存储于存储空间中某个特定分区的情况,此时如果您的请求速率过大,会导致请求速率下降。建议您在上传大量文件时,不要使用顺序前缀的文件名。将顺序前缀改为随机性前缀的方法请参见OSS性能与扩展性最佳实践
  • OSS的文件上传默认会覆盖同名文件, 为防止文件被意外覆盖,您可以通过以下方式保护您的文件。
    • 开启版本控制功能

      开启版本控制功能后,被删除或覆盖的文件会以历史版本的形式保存下来。您可以随时恢复历史版本文件。详情请参见版本控制介绍

    • 在上传请求中携带禁止覆盖同名文件的参数

      在上传请求的表单域中携带x-oss-forbid-overwrite,并指定其值为true。当您上传的文件在OSS中存在同名文件时,该文件会上传失败,并返回FileAlreadyExists错误。更多详情请参见PostObject

      当不携带此参数或此参数的值为false时,同名文件会被覆盖。

流程解析

  1. 构建一个Post Policy。

    Post请求的Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名称等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。具体请参见Post Policy

    以Python代码为例子,Policy是json格式的字符串。
    # 设置网站用户能上传文件的过期时间为2115-01-27T10:56:19Z(这里为了测试成功写的过期时间很长,实际使用中不建议这样设置),文件大小不超过104857600字节
    policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 104857600]]}"
  2. 将Policy字符串进行base64编码。
  3. 用OSS的AccessKeySecret对base64编码后的Policy进行签名。
  4. 构建上传的HTML页面。
  5. 打开HTML页面,选择文件上传。

完整Python代码示例:

#coding=utf8
import md5
import hashlib
import base64
import hmac
from optparse import OptionParser
def convert_base64(input):
    return base64.b64encode(input)
def get_sign_policy(key, policy):
    return base64.b64encode(hmac.new(key, policy, hashlib.sha1).digest())
def get_form(bucket, endpoint, access_key_id, access_key_secret, out):
    #1 构建一个Post Policy
    policy="{\"expiration\":\"2115-01-27T10:56:19Z\",\"conditions\":[[\"content-length-range\", 0, 1048576]]}"
    print("policy: %s" % policy)
    #2 将Policy字符串进行base64编码
    base64policy = convert_base64(policy)
    print("base64_encode_policy: %s" % base64policy)
    #3 用OSS的AccessKeySecret对编码后的Policy进行签名
    signature = get_sign_policy(access_key_secret, base64policy)
    #4 构建上传的HTML页面
    form = '''
    <html>
        <meta http-equiv=content-type content="text/html; charset=UTF-8">
        <head><title>OSS表单上传(PostObject)</title></head>
        <body>
            <form  action="http://%s.%s" method="post" enctype="multipart/form-data">
                <input type="text" name="OSSAccessKeyId" value="%s">
                <input type="text" name="policy" value="%s">
                <input type="text" name="Signature" value="%s">
                <input type="text" name="key" value="upload/${filename}">
                <input type="text" name="success_action_redirect" value="http://oss.aliyun.com">
                <input type="text" name="success_action_status" value="201">
                <input name="file" type="file" id="file">
                <input name="submit" value="Upload" type="submit">
            </form>
        </body>
    </html>
    ''' % (bucket, endpoint, access_key_id, base64policy, signature)
    f = open(out, "wb")
    f.write(form)
    f.close()
    print("form is saved into %s" % out)
if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option("", "--bucket", dest="bucket", help="specify ")
    parser.add_option("", "--endpoint", dest="endpoint", help="specify")
    parser.add_option("", "--id", dest="id", help="access_key_id")
    parser.add_option("", "--key", dest="key", help="access_key_secret")
    parser.add_option("", "--out", dest="out", help="out put form")
    (opts, args) = parser.parse_args()
    if opts.bucket and opts.endpoint and opts.id and opts.key and opts.out:
        get_form(opts.bucket, opts.endpoint, opts.id, opts.key, opts.out)
    else:
        print "python %s --bucket=your-bucket --endpoint=oss-cn-hangzhou.aliyuncs.com --id=your-access-key-id --key=your-access-key-secret --out=out-put-form-name" % __file__

将此段代码保存为post_object.py,然后用python post_object.py来运行。

使用方法:
python post_object.py --bucket=您的Bucket --endpoint=Bucket对应的OSS域名 --id=您的AccessKeyId --key=您的AccessKeySecret --out=输出的文件名
使用示例:
python post_object.py --bucket=oss-sample --endpoint=oss-cn-hangzhou.aliyuncs.com --id=tphpxp --key=ZQNJzf4QJRkrH4 --out=post.html
说明
  • 构建的表单中success_action_redirect value=http://oss.aliyun.com 表示上传成功后跳转的页面。可以替换成您自己的页面。
  • 构建的表单中success_action_status value=201表示的是上传成功后返回的状态码为201,可以替换。
  • 假如指定生成的HTML文件为post.html,打开post.html,选择文件上传。在这个例子中如果成功则会跳转到OSS的主页面。

上传的安全及授权

为了防止第三方未经授权往您的Bucket里上传数据,OSS提供了Bucket和Object级别的访问权限控制。详情请参见权限控制

为了授权给第三方上传,OSS还提供了账号级别的授权。详情请参见授权给第三方上传