本文主要介紹上傳回調中的常見錯誤及分析處理。
關於上傳回調
OSS在檔案上傳完成時可以提供回調(Callback)給使用者的回調伺服器(Callback Server)。在上傳請求中攜帶相應的回調參數,即能實現上傳回調。支援上傳回調的 API 介面有:PutObject、PostObject、CompleteMultipartUpload。更詳細的介紹請參見開發指南中的上傳回調和Callback API。
回調伺服器(Callback Server),有時也叫商務服務器。
應用情境
通知
上傳回調的一種典型應用是授權的第三方上傳檔案時指定回調參數。上傳完成後OSS向回調伺服器發送回調請求。回調伺服器收到回調請求後,記錄上傳資訊。
處理、審查、統計等
回調伺服器收到回調請求後,對上傳的檔案做處理、審查、統計等。
資料流
OSS上傳回調流程解釋如下:
資料流 | 含義 | 說明 |
1 | 上傳檔案並攜帶回調參數。格式請參見PostObject。 | 通過SDK調用API介面(PutObject、CompleteMultipartUpload、PostObject)完成。 |
2 | OSS隱藏檔後發起回調 | OSS向上傳請求中指定的CallbackUrl發起POST請求,回調逾時時間是5秒。 逾時時間為固定值,不支援配置。 回調請求POST的格式請參見發起回調請求。 |
3 | 回調伺服器返回處理結果 |
|
4 | OSS返回上傳、回調結果 |
|
SDK/PostObject
上傳時可以通過設定回調參數,指定回調伺服器URL、發送給回調伺服器的資料、格式等。回調伺服器處理回調時,需要一些上下文資訊,如bucket
、object
等,通過系統變數指定;系統變數以外的上下文資訊,通過自訂變數指定。
上傳回調包括以下參數:
欄位 | 含義 | 說明 |
callbackUrl | 回調伺服器位址 | 必選參數 |
callbackHost | 回調請求訊息頭中 | 選擇性參數,預設為 |
callbackBody | 回調請求的訊息體 | 必選參數,內容可以包括系統變數和自訂變數 |
callbackBodyType | 回調請求訊息頭中 | 選擇性參數,支援 |
通過上傳請求攜帶上傳回調參數有兩種實現方式:
通過訊息頭中的
x-oss-callback
,攜帶回調參數。這種方式比較常用,推薦該方式。通過QueryString的
callback
,攜帶回調參數。
x-oss-callback
或callback
的值建置規則如下:
Callback := Base64(CallbackJson)
CallbackJson := '{' CallbackUrlItem, CallbackBodyItem [, CallbackHostItem, CallbackBodyTypeItem] '}'
CallbackUrlItem := '"'callbackUrl'"' ':' '"'CallbackUrlValue'"'
CallbackBodyItem := '"'callbackBody'"' ':' '"'CallbackBodyValue'"'
CallbackHostItem := '"'callbackHost'"' ':' '"'CallbackHostValue'"'
CallbackBodyTypeItem := '"'callbackBodyType'"' : '"'CallbackBodyType'"'
CallbackBodyType := application/x-www-form-urlencoded | application/json
CallbackJson
的值,樣本如下:
{
"callbackUrl" : "http://abc.com/test.php",
"callbackHost" : "oss-cn-hangzhou.aliyuncs.com",
"callbackBody" : "{\"bucket\":${bucket}, \"object\":${object},\"size\":${size},\"mimeType\":${mimeType},\"my_var\":${x:my_var}}",
"callbackBodyType" : "application/json"
}
或
{
"callbackUrl" : "http://abc.com/test.php",
"callbackBody" : "bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&my_var=${x:my_var}"
}
系統變數及自訂變數
CallbackJson
樣本中的 callbackBody
包括如${bucket}
、${object}
、${size}
的變數,即為OSS定義的系統變數,OSS回調時會用實際值替換掉系統變數。OSS定義的系統變數如下表:
變數 | 含義 |
${bucket} | 儲存空間名稱 |
${object} | 檔案名稱 |
${etag} | 檔案的ETag |
${size} | 檔案大小 |
${mimeType} | 檔案類型,如image/jpeg等 |
${imageInfo.height} | 圖片高度 |
${imageInfo.width} | 圖片寬度 |
${imageInfo.format} | 圖片格式,如jpg、png等 |
系統變數大小寫敏感。
系統變數的格式為
${bucket}
。imageInfo針對於圖片格式,非圖片格式值為空白。
CallbackJson
樣本中的callbackBody
包括如${x:my_var}
的變數,即自訂變數,OSS回調時會用自訂的值替換掉自訂變數。自訂變數的值可以在上傳請求中定義並攜帶,有以下兩種方式:
通過訊息頭中的
x-oss-callback-var
,攜帶自訂變數。這種方式比較常用,也是推薦方式。通過QueryString的
callback-var
,攜帶自訂變數。
x-oss-callback-var
或 callback-var
的建置規則如下:
CallbackVar := Base64(CallbackVarJson)
CallbackVarJson := '{' CallbackVarItem [, CallbackVarItem]* '}'
CallbackVarItem := '"''x:'VarName'"' : '"'VarValue'"'
CallbackVarJson
值的樣本如下:
{
"x:my_var1" : "value1",
"x:my_var2" : "value2"
}
自訂變數必須以x:開頭,大小寫敏感,格式為
${x:my_var}
。自訂變數的長度受訊息頭、URL的長度限制,建議自訂變數不超過10個,總長度不超過512Byte。
SDK使用樣本
部分SDK對上述步驟進行了封裝,如Java、JS,部分SDK需要使用上面的規則產生上傳回調參數和自訂變數,如Python、PHP、C。SDK的使用樣本如下:
SDK | 上傳回調樣本 | 說明 |
Java | 注意 | |
Python | - | |
PHP | 上傳的$options中 | |
C# | 使用using讀取 | |
JS | - | |
C | - | |
Ruby | - | |
iOS |
| |
Android | 注意 |
Go SDK暫不支援上傳回調。
PostObject使用樣本
PostObject支援上傳回調,回調參數通過表單域callback
攜帶,自訂變數通過獨立的表單域攜帶,詳情請參見PostObjet。
PostObject的使用樣本如下:
SDK | 上傳回調樣本 |
Java | |
Python | |
JS | |
C# |
回調伺服器
回調伺服器(Callback Server),是一個HTTP伺服器,處理OSS發送的回調請求,POST訊息。回調伺服器的URL即上傳回調參數中的callbackUrl
。回調伺服器是使用者自己實現的處理邏輯,實現上傳資料的記錄、審查、處理、統計等。
回調簽名
回調伺服器為了確認收到的POST請求來自於OSS的上傳回調,需要驗證該POST訊息的簽名。回調伺服器也可以不驗證簽名,直接處理該訊息。為了提高回調伺服器的安全性,建議驗證訊息簽名。回調簽名規則請參見回調簽名。
說明OSS的回調伺服器樣本中提供了簽名校正的實現,推薦直接使用該部分代碼。
訊息處理
回調伺服器的主要邏輯,對OSS的回調請求進行處理。以下幾點請注意:
回調伺服器必須處理OSS的POST請求;
OSS回調的逾時時間是5秒,回調伺服器必須在5秒內完成處理並返回;
回調伺服器返回給OSS的訊息體必須是JSON格式;
回調伺服器是使用者自己的邏輯,OSS提供樣本而不提供具體商務邏輯實現。
實現樣本
回調伺服器的實現樣本如下:
語言
樣本
運行方法
Java
解壓後執行
java -jar oss-callback-server-demo.jar 9000
。PHP
Apache環境下部署運行。
Python
解壓後執行
python callback_app_server.py
。Ruby
執行
ruby aliyun_oss_callback_server.rb
。
調試步驟
上傳回調的調試分為兩部分:上傳的用戶端、處理回調的回調伺服器。建議先調試用戶端上傳部分,再調試回調伺服器部分。兩部分單獨調試完成後,再運行完整的上傳回調。
調試用戶端
用戶端調試時,可使用OSS提供的回調伺服器
http://oss-demo.aliyuncs.com:23450
,即回調參數callbackUrl
。該回調伺服器只驗證回調請求的簽名,對回調請求不做處理。對於簽名驗證成功的回調請求,返回{"Status":"OK"}
;簽名驗證失敗的回調請求,返回400 Bad Request
;非POST請求返回501 Unsupported method
。樣本回調伺服器的代碼請參見callback_app_server.py.zip。調試回調伺服器
回調伺服器是一個支援處理POST請求的HTTP伺服器,可以在OSS提供的樣本基礎上修改,也可以自己獨立實現。OSS提供的回調伺服器樣本:
語言
樣本
運行方法
Java
解壓後執行
java -jar oss-callback-server-demo.jar 9000
。PHP
Apache環境下部署運行。
Python
解壓後執行
python callback_app_server.py
。C#
編譯後執行
aliyun-oss-net-callback-server.exe 127.0.0.1 80
。Go
編譯後執行
aliyun_oss_callback_server
。Ruby
執行
ruby aliyun_oss_callback_server.rb
。回調伺服器可以通過cURL命令調試,下面幾個命令可能會用到:
# 向回調伺服器發送訊息體為 `object=test_obj` 的 `POST` 請求,可以使用如下命令 curl -d "object=test_obj" http://oss-demo.aliyuncs.com:23450 -v # 向回調伺服器發送訊息體為檔案 `post.txt` 內容的 `POST` 請求,可以使用如下命令 curl -d @post.txt http://oss-demo.aliyuncs.com:23450 -v #向回調伺服器發送訊息體為檔案 `post.txt` 內容的 `POST` 請求,並攜帶指定的訊息頭 `Content-Type` curl -d @post.txt -H "Content-Type: application/json" http://oss-demo.aliyuncs.com:23450 -v
說明調試回調伺服器時,可以先忽略簽名驗證部分,因為
cURL
類比簽名功能比較困難。簽名驗證功能OSS樣本中已經提供,建議直接使用。
回調伺服器建議有日誌功能,記錄收到的所有訊息,方便調試、跟蹤。
回調伺服器正確處理回調請求後,一定要返回200,而不是其它的
20x
。回調伺服器返回給OSS的訊息體,一定要是JSON格式,
Content-Type
設定為application/json
。
常見錯誤及原因
InvalidArgument
<Error> <Code>InvalidArgument</Code> <Message>The callback configuration is not json format.</Message> <RequestId>587C79A3DD373E2676F73ECE</RequestId> <HostId>bucket.oss-cn-hangzhou.aliyuncs.com</HostId> <ArgumentName>callback</ArgumentName> <ArgumentValue>{"callbackUrl":"8.8.8.8:9090","callbackBody":"{"bucket":${bucket},"object":${object}}","callbackBodyType":"application/json"}</ArgumentValue> </Error>
說明回調參數設定錯誤,或參數格式錯誤。常見的錯誤是
ArgumentValue
之間的回調參數,不是有效JSON格式。在 JSON中\
、"
是逸出字元,如"callbackBody":"{"bucket":${bucket},"object":${object}}"
應該為"callbackBody":"{\"bucket\":${bucket},\"object\":${object}}"
。針對具體的SDK,請參見對應的上傳回調樣本,詳細請參考SDK使用樣本部分。轉義後的字元
轉義前的字元
\\
\\\\
\"
\\\”
\b
\\b
\f
\\f
\n
\\n
\r
\\r
\t
\\t
CallbackFailed
CallbackFailed 常見樣本如下:
樣本1:
<Error> <Code>CallbackFailed</Code> <Message>Response body is not valid json format.</Message> <RequestId>587C81A125F797621829923D</RequestId> <HostId>bucket.oss-cn-hangzhou.aliyuncs.com</HostId> </Error>
說明回調伺服器返回給OSS的訊息體非JSON格式。您可以通過
curl -d "<Content>" <CallbackServerURL> -v
或抓包確認內容。Windows下推薦使用工具Wireshark 抓包,Linux下使用命令tcpdump抓包。一些非法返回訊息體如下:OK
,\357\273\277{"Status":"OK"}
(即含有ef bb bf
三個位元組的BOM頭)等。樣本2:
<Error> <Code>CallbackFailed</Code> <Message>Error status : -1.OSS can not connect to your callbackUrl, please check it.</Message> <RequestId>587C8735355BE8694A8E9100</RequestId> <HostId>bucket.oss-cn-hangzhou.aliyuncs.com</HostId> </Error>
說明回調伺服器處理時間超過5秒,OSS認為逾時。建議回調伺服器的處理邏輯修改為非同步,保證在5秒內處理完畢並返回結果給OSS。
樣本3:
<Error> <Code>CallbackFailed</Code> <Message>Error status : -1 8.8.8.8:9090 reply timeout, cost:5000ms, timeout:5000ms (err -4, errno115)</Message> <RequestId>587C8D382AE0B92FA3EEF62C</RequestId> <HostId>bucket.oss-cn-hangzhou.aliyuncs.com</HostId> </Error>
說明回調伺服器處理時間超過5秒,OSS認為逾時。
樣本4:
<Error> <Code>CallbackFailed</Code> <Message>Error status : 400.</Message> <RequestId>587C89A02AE0B92FA3C7981D</RequestId> <HostId>bucket.oss-cn-hangzhou.aliyuncs.com</HostId> </Error>
說明回調伺服器返回給OSS的訊息的狀態代碼是
400
,請檢查回調伺服器的處理邏輯。樣本5:
<Error> <Code>CallbackFailed</Code> <Message>Error status : 502.</Message> <RequestId>587C8D382AE0B92FA3EEF62C</RequestId> <HostId>bucket.oss-cn-hangzhou.aliyuncs.com</HostId> </Error>
說明回調伺服器未啟動,或者缺少上傳回調參數中的
CallbackUrl
,或者OSS與回調伺服器的網路不通。推薦在ECS上部署回調伺服器,與OSS同屬內網可以節省流量費用,同時保證網路品質。
返回的Body非JSON格式
樣本如下:
錯誤原因有以下兩種情況。
應用伺服器返回給OSS的Body不是JSON格式。如下圖所示:
Resp_body不是合法的JSON格式,OSS就會報上述錯誤。這種一般比較明顯,還有比較隱形。例如應用伺服器處理過程中拋出異常,導致沒有按照預期返回給OSS,而是返回了一些棧資訊等。
應用伺服器返回給OSS的Body中帶有bom頭。
這類錯誤常見於用php編寫的應用伺服器中。由於php返回了bom頭,導致OSS收到的Body中多了三個位元組,不符合JSON格式,因此報上述錯誤。如果在應用伺服器端抓包,可以看到以下資訊。
上圖中ef bb bf這三個位元組就是bom頭。
說明應用伺服器返回OSS響應時,請去掉bom頭。
錯誤的status
此類錯誤較多,例如502、400等。樣本如下:
說明400或者其他的status比如404/403等是指應用伺服器返回給OSS的HTTP status是400或者404/403等,正常情況下應用伺服器必須返回200給OSS。
502是由於應用伺服器根本就沒有開啟Web服務,沒有監聽OSS發過來的回調請求。
逾時
樣本如下:
說明出於安全考慮,OSS的回調請求只會等待5秒。如果5秒後還沒有返回,那麼OSS就會主動斷開與應用伺服器的串連,並返回給用戶端逾時錯誤,錯誤資訊中的IP可以忽略。