Web端通过PostObject接口直传OBS
背景信息
常见的Web端上传方法是用户通过浏览器上传文件至应用服务器,再由应用服务器上传至OBS,数据需要在应用服务器中转,传输效率较低,且多任务同时上传时应用服务器压力大。
本文介绍一种在Web端利用PostObject接口直传文件至OBS的方法,即使用表单上传方式上传文件至OBS。如图1所示,该方案省去了应用服务器这一步骤,提高了传输效率,不会对服务器产生压力,且服务端签名后直传可以保证传输的安全性。
前提条件
已创建桶。具体操作请参见创建桶。
操作步骤
配置分为两大步:配置跨域资源共享和使用表单上传。
第一步:配置跨域资源共享
在通常的网页请求中,由于同源安全策略SOP的存在,不同域之间的网站脚本和内容是无法进行交互的。
跨域资源共享CORS是一种网络浏览器的规范机制,定义了一个域中加载的客户端Web应用程序与另一个域中的资源交互的方式。OBS支持CORS规范,允许跨域请求访问OBS中的资源。
- 在OBS管理控制台左侧导航栏选择“对象存储”。
- 在桶列表单击待操作的桶,进入对象页面。
- 在左侧导航栏,单击“访问权限控制 > CORS规则”。
- 单击“创建”,系统弹出“创建CORS规则”对话框,如图2所示。
一个桶最多可设置100条CORS规则。
- 在“CORS规则”中配置“允许的来源”、“允许的方法”、“允许的头域”、“补充头域”和“缓存时间”。
如果该OBS桶同时开启了CDN加速,CDN需配置HTTP header,详见HTTP header配置。
表1 CORS规则 参数
说明
配置建议
允许的来源
必选参数,指定允许的跨域请求的来源,即允许来自该域名下的请求访问该桶。
允许多条匹配规则,以回车换行为间隔。每个匹配规则允许使用最多一个“*”通配符。例如:
http://rds.example.com https://*.vbs.example.com
*
允许的方法
必选参数,指定允许的跨域请求方法,即桶和对象的几种操作类型。包括:Get、Post、Put、Delete、Head。
全选
允许的头域
可选参数,指定允许的跨域请求的头域。只有匹配上允许的头域中的配置,才被视为是合法的CORS请求。
允许的头域可设置多个,多个头域之间换行隔开,每行最多可填写一个*符号,不支持&、:、<、空格以及中文字符。
*
补充头域
可选参数,指CORS响应中带的补充头域,给客户端提供额外的信息。
补充头域可设置多个,多个头域之间换行隔开,不支持*、&、:、<、空格以及中文字符。
- ETag
- x-obs-request-id
- x-obs-api
- Content-Type
- Content-Length
- Cache-Control
- Content-Disposition
- Content-Encoding
- Content-Language
- Expires
- x-obs-id-2
- x-reserved-indicator
- x-obs-version-id
- x-obs-copy-source-version-id
- x-obs-storage-class
- x-obs-delete-marker
- x-obs-expiration
- x-obs-website-redirect-location
- x-obs-restore
- x-obs-version
- x-obs-object-type
- x-obs-next-append-position
缓存时间
必选参数,请求来源的客户端可以缓存的CORS响应时间,以秒为单位,默认为100秒。
根据实际业务设置。
- 单击“确定”。
“CORS规则”页签显示“创建CORS规则成功”提示创建桶的CORS配置成功。CORS配置会在两分钟内生效。
CORS配置成功后,便仅允许跨域请求来源的地址通过允许的方法访问OBS的桶。例如:为桶“testbucket”允许的来源配置为“https://www.example.com”,允许的方法配置为“GET”,允许的头域配置为“*”,补充头域配置为“ETag”,缓存时间设置为“100”,则OBS仅允许来源为“https://www.example.com”的“GET”请求访问桶“testbucket”,且不限制该请求的头域,允许响应中返回ETag值,请求来源的客户端可缓存的该CORS请求的响应时间为100秒。
第二步:使用表单上传
以BrowserJS为例,演示如何直接使用SDK计算签名。
基于表单上传是使用HTML表单形式上传对象到指定桶中,对象最大不能超过5GB。
您可以通过ObsClient.createPostSignatureSync生成基于表单上传的请求参数。使用BrowserJS代码模拟表单上传的完整代码示例,可单击此处下载:post-object-sample。您也可以通过如下步骤进行表单上传:
- 使用ObsClient.createPostSignatureSync生成用于鉴权的请求参数。
使用SDK生成用于鉴权的请求参数包括两个:
- Policy:对应表单中policy字段。
- Signature:对应表单中的signature字段。
代码示例如下:// 创建ObsClient实例 var obsClient = new ObsClient({ // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量AccessKeyID和SecretAccessKey。 // 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html access_key_id: process.env.AccessKeyID, secret_access_key: process.env.SecretAccessKey, server : 'https://your-endpoint', signature : 'obs' }); // 设置表单参数 var formParams = { // 设置对象访问权限为公共读 'x-obs-acl': obsClient.enums.AclPublicRead, // 设置对象MIME类型 'content-type': 'text/plain' }; // 设置表单上传请求有效期,单位:秒 var expires = 3600; var res = obsClient.createPostSignatureSync({Expires:expires, FormParams: formParams}); // 获取表单上传请求参数 console.log('\t' + res.Policy); console.log('\t' + res.Signature);
- 准备表单HTML页面。
表单HTML代码示例如下:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <form action="http://bucketname.your-endpoint/" method="post" enctype="multipart/form-data"> Object key <!-- 对象名 --> <input type="text" name="key" value="objectname" /> <p> ACL <!-- 对象ACL权限 --> <input type="text" name="x-obs-acl" value="public-read" /> <p> Content-Type <!-- 对象MIME类型 --> <input type="text" name="content-type" value="text/plain" /> <p> <!-- policy的base64编码值 --> <input type="hidden" name="policy" value="*** Provide your policy ***" /> <!-- AK --> <input type="hidden" name="AccessKeyId" value="*** Provide your access key ***"/> <!-- 签名串信息 --> <input type="hidden" name="signature" value="*** Provide your signature ***"/> <input name="file" type="file" /> <input name="submit" value="Upload" type="submit" /> </form> </body> </html>
- HTML表单中的policy,signature的值均是从ObsClient.createPostSignatureSync的返回结果中获取。
- 表单HTML示例可单击此处下载:PostDemo。
- 将生成的请求参数填入HTML页面。
- 选择本地文件,进行表单上传。
知识扩展
采用BrowserJS SDK直接计算签名时,AK/SK可能会展现在前端界面,有一定风险。
您还可以采用客户端-服务端模型,服务端可以采用Java、Python等SDK计算POST上传签名,客户端采用JavaScript向服务端获取签名信息后利用签名信息访问OBS。
其中,计算POST上传签名信息请参考各SDK语言:
除POST上传外,在其他场景中,为了避免前端代码直接使用AK/SK访问OBS造成敏感信息泄露,可以通过后台计算临时URL,前端使用临时URL授权访问OBS。
利用GO SDK计算临时URL,前端JS使用临时URL列举OBS桶内对象。示例如下:
- GO SDK后台计算列举桶临时URL。
// 引入依赖包 import ( "fmt" "obs" "strings" ) //推荐通过环境变量获取AKSK,这里也可以使用其他外部引入方式传入,如果使用硬编码可能会存在泄露风险。 //您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html。 var ak = os.Getenv("AccessKeyID") var sk = os.Getenv("SecretAccessKey") var endpoint = "https://your-endpoint" // 创建ObsClient结构体 var obsClient, _ = obs.New(ak, sk, endpoint) func main() { input := &obs.CreateSignedUrlInput{} input.Expires = 3600 // 生成列举对象临时URL // 指定为GET请求,传入桶名 input.Method = obs.HttpMethodGet input.Bucket = "bucketname" output, _ := obsClient.CreateSignedUrl(input) // 获取生成的临时URL及请求头域信息 fmt.Printf("SignedUrl:%s\n", output.SignedUrl) fmt.Printf("ActualSignedRequestHeaders:%v\n", output.ActualSignedRequestHeaders) }
- 前台获取到签名URL SignedUrl及请求头域信息ActualSignedRequestHeaders后,访问OBS进行列举桶操作。
// 使用GET请求获取对象列表 var bucketName = 'bucketname'; var method = 'GET'; // SignedUrl为上一步骤中后端服务计算得到的临时URL, // ActualSignedRequestHeaders为上一步骤中后端服务计算临时URL时使用的请求头域,前台实际请求应保持一致; var reopt = { method : method, url : SignedUrl, withCredentials: false, headers : ActualSignedRequestHeaders || {}, validateStatus: function(status){ return status >= 200; }, maxRedirects : 0, responseType : 'text', }; axios.request(reopt).then(function (response) { if(response.status < 300){ console.log('Listing object using temporary signature succeed.'); }else{ console.log('Listing object using temporary signature failed!'); console.log('status:' + response.status); console.log('\n'); } console.log(response.data); console.log('\n'); }).catch(function (err) { console.log('Listing object using temporary signature failed!'); console.log(err); console.log('\n'); });
其中,生成临时授权访问URL请参考各SDK语言: