华为云对象存储表单上传
每个华为云对象存储的用户,都会用到上传。大多数都是在服务器通过 SDK 上传到华为云对象存储。然而很多应用对在浏览器上传文件到 华为云对象存储 的需求很强烈,采用的做法是用户在浏览器上传到应用服务器,然后应用服务器再把文件上传到 华为云对象存储。 这种方法有三个缺点:
第一:上传慢。先上传到应用服务器,再上传到 华为云对象存储,网络传送多了一倍。如果数据直传到华为云对象存储,不走应用服务器,速度将大大提升。
第二:费用高。由于 华为云对象存储 上传流量是免费的。如果数据直传到 华为云对象存储,不走应用服务器,将节省应用服务器的带宽。
第三:开发维护代价高。应用服务器需要开发相关接收并转发数据到 华为云对象存储 的功能。后期还存在扩展维护等开销。
华为云对象存储表单直传
表单直传就是在浏览器通过 JaveScript 生成表单直接上传到 华为云对象存储。包括用于鉴权的 Signature,文件名字段 key 等连同文件一起封装成表单直接上传到 华为云对象存储。 表单内容参考如下:
------WebKitFormBoundaryVDu6DqT79PvZYSgZ
Content-Disposition: form-data; name="AWSAccessKeyId" //access key
9cea0fc32fa742fe811e75bd26112ecb
------WebKitFormBoundaryVDu6DqT79PvZYSgZ
Content-Disposition: form-data; name="policy"
eyJjb25kaXRpb25zIjogW3siYnVja2V0IjogImZvcm1wb3N0In0sIFsic3RhcnRzLXdpdGgiLCAiJGtleSIsICJ1cGxvYWQvIl1dLCAiZXhwaXJhdGlvbiI6ICIyMDE3LTEyLTAxVDAwOjAwOjAwWiJ9Cgo=
------WebKitFormBoundaryVDu6DqT79PvZYSgZ
Content-Disposition: form-data; name="signature" // signature
MC56JWFf58SSV23/pPss8aM4XXM=
------WebKitFormBoundaryVDu6DqT79PvZYSgZ
Content-Disposition: form-data; name="key" // 文件名(key)
upload/js2017
------WebKitFormBoundaryVDu6DqT79PvZYSgZ
Content-Disposition: form-data; name="file"; filename="js2017"
Content-Type: application/octet-stream
hello js // 文件内容:hello js
------WebKitFormBoundaryVDu6DqT79PvZYSgZ
Content-Disposition: form-data; name="submit"
Upload
------WebKitFormBoundaryVDu6DqT79PvZYSgZ--
policy解析
base64 -D <<< 'eyJjb25kaXRpb25zIjogW3siYnVja2V0IjogImZvcm1wb3N0In0sIFsic3RhcnRzLXdpdGgiLCAiJGtleSIsICJ1cGxvYWQvIl1dLCAiZXhwaXJhdGlvbiI6ICIyMDE3LTEyLTAxVDAwOjAwOjAwWiJ9Cgo='
{"conditions": [
{"bucket": "formpost"}, # 表示上传的Bucket为formpost
["starts-with", "$key", "upload/"] # 上传的文件名需以upload/开头
],
"expiration": "2017-12-01T00:00:00Z" # 此policy在2017.12.01之前有效
}
表单上传鉴权
文件上传需要通过鉴权。表单上传鉴权(singnature)的生成可以在浏览器直接填写 access key 和 secret key 生成。但是这样会暴露 secret key,带来安全隐患。 我们这里采用向后台申请获得 access key、policy 和 signature 的方式来完成上传。示意图如下: 表单上传鉴权
应用后台开发示例
#-*- coding:utf-8 -*-
import BaseHTTPServer
import base64, json
import hmac, hashlib
import sys,os
host = "华为云对象存储test-corp.sankuai.com"
bucket = "formpost"
upload_dir = "upload"
access_key = "**"
secret_key = "**"
def formpost_token():
policy_dict = {
"expiration": "2017-12-01T00:00:00Z",
"conditions": [
{"bucket": bucket},
["starts-with", "$key", upload_dir], // 表示上传文件名只能以upload/开头
]
}
policy_document = json.dumps(policy_dict)
policy = base64.b64encode(policy_document)
signature = base64.b64encode(hmac.new(secret_key, policy, hashlib.sha1).digest())
formFields = [
('key', 'upload/${filename}'),
('AWSAccessKeyId', access_key),
('signature', signature),
('policy', policy)
]
token_dict = {}
token_dict['accessid'] = access_key
token_dict['host'] = host
token_dict['policy'] = policy
token_dict['signature'] = signature
token_dict['dir'] = upload_dir
result = json.dumps(token_dict)
return result
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
try:
token = formpost_token()
self.send_content(token)
except Exception as msg:
self.handle_error(msg)
def handle_error(self, msg):
self.send_content(msg, 404)
def send_content(self, content, status=200):
self.send_response(status)
self.send_header("Content-type", "text/html")
self.send_header("Origin", "*")
self.send_header("Content-Length", str(len(content)))
self.send_header("Access-Control-Allow-Headers", "content-type,x-auth-token")
self.send_header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Expose-Headers", "Cache-Control,Content-Type,Expires,Last-Modified,ETag,X-Timestamp,X-华为云对象存储-Trace-id,X-Container-Object-Count,X-Container-Bytes-Used,X-Account-Container-Count,X-Account-Object-Count,X-Account-Bytes-Used,X-Static-Large-Object,X-Container-Read,X-Container-Write,X-Auth-Token")
self.end_headers()
self.wfile.write(content)
if __name__ == '__main__':
serverAddress = ('', 8000)
server = BaseHTTPServer.HTTPServer(serverAddress, RequestHandler)
server.serve_forever()
表单上传操作
创建应用后台程序并写入示例代码,然后启动应用后台程序
点击这里,打开表单上传 JS 页面
在 Application URL 填写应用后台地址(例子中的地址为http://10.4.240.234:8000),然后点击 Set Application URL,会在表单域示例产生 AWSAccessKeyId、policy 和 signature 三项
在 Post URL 填写上传地址,示例中上传的桶名为 formpost,然后点击 Set URL
如果想修改默认文件名,可以删除表单域 key。然后新添加表单域 Name:key,Value 字段需以 upload/ 作为前缀(匹配 policy 里面的 key)
添加上传文件,示例添加的文件名为js2017
点击 Upload 按钮完成上传
发表评论