
# 使用上传回调获取对象信息
#### 使用场景
您可以通过回调，获取对象上传后的相关信息，例如获取对象是否上传成功，获取对象Etag、上传后大小、上传后对象所在桶等信息。OBS支持通过回调获取对象的系统参数和自定义参数，参数详情可参考API参考的[回调](https://support.huaweicloud.com/api-obs/obs_04_0095.html)章节。
图1上传回调流程图   
![](https://support.huaweicloud.com/usermanual-obs/figure/zh-cn_image_0000001833427752.png "点击放大")
上传回调的详细流程如[图1]所示，主要分为以下几个阶段：
1. 客户端发出上传对象请求，请求中携带回调参数。
2. OBS接收到客户端的上传请求，执行上传对象操作。对象上传成功后，OBS封装回调请求。
3. OBS调用回调接口，向回调服务器发起回调请求。
4. 回调服务器得到上传对象完成的通知，完成数据更新，处理回调请求。
5. 回调服务器将回调响应数据返回给OBS。
6. OBS将上传对象请求的响应结果返回给客户端，响应结果中携带回调数据。
 
#### 约束与限制
- 目前只在POST上传对象、PUT上传对象以及合并段API中支持回调功能。
- 在对象上传成功之后才会回调特定服务器，如果对象上传失败则不会回调。
- 如果上传的图片大小超过25M，则无法通过imageInfo相关系统变量获取图片基本信息，会导致回调失败。
 
#### 使用方式
OBS支持通过API、SDK方式使用上传回调，不支持通过[管理控制台](https://console.huaweicloud.com/console/?locale=zh-cn#/obs/manager/buckets)、OBS Browser+、obsutil方式使用上传回调。
#### 使用API
[回调](https://support.huaweicloud.com/api-obs/obs_04_0095.html)
#### 使用SDK
| Java：不支持 | Python：不支持 | C：不支持 | [Go](https://support.huaweicloud.com/sdk-go-devg-obs/obs_33_0605.html) | BrowserJS：不支持 | .NET：不支持 | Android：不支持 | iOS：不支持 | PHP：不支持 | Node.js：不支持 |
|---|---|---|---|---|---|---|---|---|---|
   
#### 回调签名验证
如果您在上传对象请求中设置回调参数，OBS在对象上传成功之后，将上传结果回调特定服务器，并将回调结果返回给您。回调结果中包含签名信息，以下介绍如何校验回调结果中的签名信息。
OBS回调您的服务器时，会在请求头中携带"Authorization"和 "x-signature-time"。您可以使用自己的SK重新计算签名，与请求头中的签名比对，验证请求确实来自OBS。
验证签名主要分为以下四步：
1. **从回调请求头取出"x-signature-time"的值。**
2. **拼接待签名字符串：*回调URL路径* + 换行 + *回调body体替换后的内容* + 换行 + *x-signature-time***
   ```
   回调URL路径
   回调body体替换后的内容
   x-signature-time
   ```
   回调body体中的变量在回调时会被替换为实际值，替换规则如[表1]：
    表1回调body体中的变量替换规则 
   | 变量     | 替换为                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | 示例           |
   |:---|:---|:---|
   | bucket | 桶名称。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | my-bucket    |
   | key    | 对象名原始值。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | test.txt     |
   | fsize  | 对象大小，单位：字节。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | 100          |
   | etag   | 对象的ETag。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | -            |
   | fname  | 对象名。该参数的替换值与回调body体类型有关： - 回调body体类型为"application/x-www-form-urlencoded" ：替换为对象名的 Base64 编码。 例如："test.txt"替换为"dGVzdC50eHQ="。   - 回调body体类型为"application/json" ：替换为对象名原始值。 例如："test.txt"替换为"test.txt"。    | dGVzdC50eHQ= |
      
   
3. **使用SK对待签名字符串做HMAC-SHA256，再做Base64编码。**
4. **比对计算结果与"Authorization"中"OBS \<AK\>:"后面的签名，如果一致则验证通过。**
以下通过示例来介绍如何校验回调结果中的签名信息：
表2示例的场景对比 
| 对比项              | 示例一                               | 示例二                                        | 示例三                             |
|:---|:---|:---|:---|
| 上传方式             | POST                              | POST                                       | PUT                             |
| 回调body体类型        | application/x-www-form-urlencoded | application/json                           | application/json                |
| 回调body体模板        | fsize=$(fsize)\&fname=$(fname)    | {"fsize": "$(fsize)", "fname": "$(fname)"} | bucket=$(bucket)\&object=$(key) |
| $(fname)替换       | Base64编码                          | 原始值                                        | 原始值                             |
| StringToSign中的格式 | key=value                         | {"key": "value"}                           | key=value                       |
   
![](https://support.huaweicloud.com/usermanual-obs/public_sys-resources/caution_3.0-zh-cn.png)
- StringToSign中的回调body体替换后的内容和您配置的模板格式保持一致，即如果您配置的回调body体为"bucket=$(bucket)\&object=$(key)"，则替换后的内容为"bucket=桶名\&object=对象名"，不会因为回调body体类型为"application/json"就自动转成JSON格式。回调body体类型只影响回调请求的Content-Type和请求体格式，不影响签名计算。
- 中文对象名与英文对象名的签名逻辑完全一致，仅替换后的输入值不同。application/x-www-form-urlencoded类型下，中文对象名经Base64编码后回调参数通过URL传递，可能会由于中文被二次编码而产生编码问题，因此建议中文场景优先使用application/json类型。
- PUT上传和POST上传的签名算法完全一样。签名算法始终是"Base64(HMAC-SHA256(SK, StringToSign))"，区别仅在于回调配置的传递方式：POST通过 Policy表单字段，PUT通过"x-obs-callback"请求头。
 
#### 示例一：POST上传 + application/x-www-form-urlencoded
表3配置说明 
| 配置        | 实际值                                 |
|:---|:---|
| 上传方式      | POST表单上传                            |
| 回调body体   | fsize=$(fsize)\&fname=$(fname)      |
| 回调body体类型 | application/x-www-form-urlencoded   |
| 回调URL     | http://example.com/fetchjobcallback |
| 上传的对象名    | test.txt                            |
| 上传的对象大小   | 100字节                               |
   
回调body体替换后的内容为：**fsize=100\&fname=dGVzdC50eHQ=**，其中$(fsize)为对象大小100，$(fname)替换为对象名"test.txt"的 Base64 编码"dGVzdC50eHQ="。
假设OBS回调您的服务器时，在请求头中携带"x-signature-time"的值为"1781754606"，则拼接的待签名字符串为：
```
/fetchjobcallback
fsize=100&fname=dGVzdC50eHQ=
1781754606
```
- **计算签名**
  使用SK对待签名字符串做HMAC-SHA256，再做Base64编码。
  ```
  import hmac, hashlib, base64
  sk = "您的SK"
  string_to_sign = "/fetchjobcallback\nfsize=100&fname=dGVzdC50eHQ=\n1781754606"
  sig = base64.b64encode(
      hmac.new(sk.encode('UTF-8'), string_to_sign.encode('UTF-8'), hashlib.sha256).digest()
  ).decode('UTF-8')
  ```
  
- **OBS 发出的回调请求**
  ```
  POST /fetchjobcallback?fsize=100&fname=dGVzdC50eHQ= HTTP/1.1
  Host: 127.0.0.1:12334
  Content-Type: application/x-www-form-urlencoded
  Authorization: OBS <AK>:<Signature>
  x-signature-time: 1781754606
  ```
  比对[计算签名]的结果与"Authorization"中的\<Signature\>，如果一致则验证通过。
  
 
#### 示例二：POST上传 + application/json
表4配置说明 
| 配置        | 实际值                                        |
|:---|:---|
| 上传方式      | POST表单上传                                   |
| 回调body体   | {"fsize": "$(fsize)", "fname": "$(fname)"} |
| 回调body体类型 | application/json                           |
| 回调URL     | http://example.com/fetchjobcallback123     |
| 上传的对象名    | 中文对象.txt                                   |
| 上传的对象大小   | 100字节                                      |
   
回调body体替换后的内容为：**{"fsize": "100", "fname": "中文对象.txt"}**，其中$(fsize)为对象大小100，$(fname)替换为对象名原始值"中文对象.txt"。
![](https://support.huaweicloud.com/usermanual-obs/public_sys-resources/note_3.0-zh-cn.png)
application/json类型下StringToSign中的回调body体格式为服务端HashMap遍历顺序序列化结果，英文冒号和英文逗号后均带空格。
假设OBS回调您的服务器时，在请求头中携带"x-signature-time"的值为"1782461537"，则拼接的待签名字符串为：
```
/fetchjobcallback
{"fsize": "100", "fname": "中文对象.txt"}
1782461537
```
- **计算签名**
  使用SK对待签名字符串做HMAC-SHA256，再做Base64编码。
  ```
  import hmac, hashlib, base64
  sk = "您的SK"
  callbackbody = '{"fsize": "100", "fname": "中文对象.txt"}'
  string_to_sign = "/fetchjobcallback123\n" + callbackbody + "\n1782461537"
  sig = base64.b64encode(
      hmac.new(sk.encode('UTF-8'), string_to_sign.encode('UTF-8'), hashlib.sha256).digest()
  ).decode('UTF-8')
  ```
  
- **OBS 发出的回调请求**
  ```
  POST /fetchjobcallback123 HTTP/1.1
  Host: 127.0.0.1:12334
  Content-Type: application/json;charset=utf-8
  Authorization: OBS <AK>:<Signature>
  x-signature-time: 1782461537
  {"fsize": "100", "fname": "中文对象.txt"}
  ```
  比对[计算签名]的结果与"Authorization"中的\<Signature\>，如果一致则验证通过。
  
 
#### 示例三：PUT上传 + application/json
表5配置说明 
| 配置        | 实际值                                |
|:---|:---|
| 上传方式      | PUT上传（通过"x-obs-callback"请求头携带回调配置） |
| 回调body体   | bucket=$(bucket)\&object=$(key)    |
| 回调body体类型 | application/json                   |
| 回调URL     | http://127.0.0.1:12335/callback    |
| 桶名        | my-bucket                          |
| 上传的对象名    | test.txt                           |
   
回调body体替换后的内容为：**bucket=my-bucket\&object=test.txt**，其中$(bucket)为桶名称"my-bucket"，$(key)为对象名的原始值"test.txt"。
![](https://support.huaweicloud.com/usermanual-obs/public_sys-resources/note_3.0-zh-cn.png)
虽然回调body体类型是application/json，但回调body体模板本身是"key=value"格式，替换后保持该格式，不会自动转成JSON格式。
假设OBS回调您的服务器时，在请求头中携带"x-signature-time"的值为"1782524313"，则拼接的待签名字符串为：
```
/callback
bucket=my-bucket&object=test.txt
1782524313
```
- **计算签名**
  使用SK对待签名字符串做HMAC-SHA256，再做Base64编码。
  ```
  import hmac, hashlib, base64
  sk = "您的SK"
  string_to_sign = "/callback\nbucket=my-bucket&object=test.txt\n1782524313"
  sig = base64.b64encode(
      hmac.new(sk.encode('UTF-8'), string_to_sign.encode('UTF-8'), hashlib.sha256).digest()
  ).decode('UTF-8')
  ```
  
- **上传请求**
  ```
  PUT /my-bucket/test.txt HTTP/1.1
  Host: obs.example.com
  x-obs-callback: <Base64编码的回调配置>
  Authorization: OBS <AK>:<上传签名>
  ```
  其中"x-obs-callback"的值为以下JSON的Base64编码：
  ```
  {
      "callbackUrl": "http://127.0.0.1:12335/callback",
      "callbackBody": "bucket=$(bucket)&object=$(key)",
      "callbackBodyType": "application/json"
  }
  ```
  
- **OBS 发出的回调请求**
  ```
  POST /callback?bucket=my-bucket&object=test.txt HTTP/1.1
  Host: 127.0.0.1:12335
  Content-Type: application/json
  Authorization: OBS <AK>:<回调签名>
  x-signature-time: 1782524313
  ```
  比对[计算签名]的结果与"Authorization"中的\<回调签名\>，如果一致则验证通过。
  
 
