
# Web端通过PostObject接口直传OBS
#### 背景信息
常见的Web端上传方法是用户通过浏览器上传文件至应用服务器，再由应用服务器上传至OBS，数据需要在应用服务器中转，传输效率较低，且多任务同时上传时应用服务器压力大。
本文介绍一种在Web端利用PostObject接口直传文件至OBS的方法，即使用表单上传方式上传文件至OBS。如[图1]所示，该方案省去了应用服务器这一步骤，提高了传输效率，不会对服务器产生压力，且服务端签名后直传可以保证传输的安全性。
图1Web端PostObject直传流程图   
![](https://support.huaweicloud.com/bestpractice-obs/zh-cn_image_0000001160439220.png)
#### 前提条件
已创建桶。具体操作请参见[创建桶](https://support.huaweicloud.com/usermanual-obs/zh-cn_topic_0045829088.html)。
#### 操作步骤
配置分为两大步：配置跨域资源共享和使用表单上传。
**第一步：配置跨域资源共享**
在通常的网页请求中，由于同源安全策略SOP的存在，不同域之间的网站脚本和内容是无法进行交互的。
跨域资源共享CORS是一种网络浏览器的规范机制，定义了一个域中加载的客户端Web应用程序与另一个域中的资源交互的方式。OBS支持CORS规范，允许跨域请求访问OBS中的资源。
1. 在OBS[管理控制台](https://console.huaweicloud.com/console/?locale=zh-cn#/obs/manager/buckets)左侧导航栏选择"桶列表"。
2. 在桶列表单击待操作的桶，进入对象页面。
3. 在左侧导航栏，单击"权限控制 \> CORS规则"。
4. 单击"创建"，系统弹出"创建CORS规则"对话框。 
   ![](https://support.huaweicloud.com/bestpractice-obs/public_sys-resources/note_3.0-zh-cn.png)
   一个桶最多可设置100条CORS规则。
   
   
   
5. 在"CORS规则"中配置"允许的来源"、"允许的方法"、"允许的头域"、"补充头域"和"缓存时间"。 
   ![](https://support.huaweicloud.com/bestpractice-obs/public_sys-resources/note_3.0-zh-cn.png)
   如果该OBS桶同时开启了CDN加速，CDN需配置HTTP header，详见[HTTP header配置](https://support.huaweicloud.com/usermanual-cdn/cdn_01_0021.html)。
   表1CORS规则 
   | 参数    | 说明                                                                                                                                                                                                                                       | 配置建议                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
   |:---|:---|:---|
   | 允许的来源 | 必选参数，指定允许的跨域请求的来源，即允许来自该域名下的请求访问该桶。 允许多条匹配规则，以回车换行为间隔。每个匹配规则允许使用最多一个"\*"通配符。例如： ``` 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秒。                                                                                                                                                                                                | 根据实际业务设置。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
      
   
   
6. 单击"确定"。 
   "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](https://obssdk.obs.cn-north-1.myhuaweicloud.com/sample/browserjs/post-object-sample.zip)。您也可以通过如下步骤进行表单上传：
1. 使用ObsClient.createPostSignatureSync生成用于鉴权的请求参数。 
   使用SDK生成用于鉴权的请求参数包括两个：
   - Policy：对应表单中policy字段。
   
   - Signature：对应表单中的signature字段。
    
   代码示例如下，请根据业务场景自行配置示例中的AK/SK、桶名、ACL等参数：
   ```
   // 创建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);
   ```
   
   
   
2. 准备表单HTML页面。 
   表单HTML代码示例如下，请根据业务场景自行配置示例中的AK/SK、桶名、对象名、ACL等参数：
   ```
   <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>
   ```
   ![](https://support.huaweicloud.com/bestpractice-obs/public_sys-resources/note_3.0-zh-cn.png)
   - HTML表单中的policy，signature的值均是从ObsClient.createPostSignatureSync的返回结果中获取。
   
   - 表单HTML示例可单击此处下载：[PostDemo](https://obssdk.obs.cn-north-1.myhuaweicloud.com/sample/browserjs/PostDemo.zip)。
    
   
   
3. 将生成的请求参数填入HTML页面。
4. 选择本地文件，进行表单上传。
 
#### 结果验证
HTML表单中包含一个文件选择框和一个上传按钮，用户可以选择想要上传的文件然后提交表单。
当表单提交时，JavaScript代码会请求服务器获取本次上传所需要的签名信息，得到正确响应之后，会构造一个FormData对象， 然后填充所有必要数据，通过fetch方法发送POST请求到OBS的服务端，完成文件上传。
图2表单上传回调示例   
![](https://support.huaweicloud.com/bestpractice-obs/zh-cn_image_0000002467760097.png "点击放大")
通过表单上传一个名为"demo-object"的文件至桶"post-callback-demo"中，上传后在OBS桶列表中的"post-callback-demo"中可以看到"demo-object"文件，即表示成功通过表单上传文件。
图3查看所上传的文件   
![](https://support.huaweicloud.com/bestpractice-obs/zh-cn_image_0000002467839949.png "点击放大")
#### 知识扩展
采用BrowserJS SDK直接计算签名时，AK/SK可能会展现在前端界面，有一定风险。
您还可以采用客户端-服务端模型，服务端可以采用Java、Python等SDK计算POST上传签名，客户端采用JavaScript向服务端获取签名信息后利用签名信息访问OBS。
其中，计算POST上传签名信息请参考各SDK语言：
- [Java](https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0612.html)
- [Python](https://support.huaweicloud.com/sdk-python-devg-obs/obs_22_0907.html)
- [PHP](https://support.huaweicloud.com/sdk-php-devg-obs/obs_28_0409.html)
- [BrowserJS](https://support.huaweicloud.com/sdk-browserjs-devg-obs/obs_24_0512.html)
- [Node.js](https://support.huaweicloud.com/sdk-nodejs-devg-obs/obs_29_0412.html)
除POST上传外，在其他场景中，为了避免前端代码直接使用AK/SK访问OBS造成敏感信息泄露，可以通过后台计算临时URL，前端使用临时URL授权访问OBS。
利用GO SDK计算临时URL，前端JS使用临时URL列举OBS桶内对象。示例如下：
1. 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)
   }
   ```
   
2. 前台获取到签名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语言：
- [Java](https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0901.html)
- [Python](https://support.huaweicloud.com/sdk-python-devg-obs/obs_22_1301.html)
- [Go](https://support.huaweicloud.com/sdk-go-devg-obs/obs_33_0601.html)
- [Node.js](https://support.huaweicloud.com/sdk-nodejs-devg-obs/obs_29_0701.html)
 
