OSS can trigger a callback after a file upload to notify your application server for post-upload processing.
Limitations
-
Region availability
Callbacks are supported in: China (Hangzhou), China (Shanghai), China (Qingdao), China (Beijing), China (Zhangjiakou), China (Hohhot), China (Ulanqab), China (Shenzhen), China (Heyuan), China (Guangzhou), China (Chengdu), China (Hong Kong), US (Silicon Valley), US (Virginia), Japan (Tokyo), Singapore, Malaysia (Kuala Lumpur), Indonesia (Jakarta), Philippines (Manila), Germany (Frankfurt), UK (London), and UAE (Dubai).
-
Callback behavior
-
A callback request must receive a response within 5 seconds. Otherwise, the request times out and fails.
-
A callback failure does not affect the completion of the file upload.
-
Failed callbacks are not automatically retried.
-
-
Supported API operations
The PutObject, PostObject, and CompleteMultipartUpload operations support callbacks. The V2 SDK file upload manager and presigned URLs also support callbacks.
How it works
The callback process:
-
Upload a file with callback parameters
The client includes callback parameters specifying the application server URL and the callback body content. You can also include the optional
callback-varparameter for custom variables. -
OSS stores the file and sends a callback request
After the file is uploaded, OSS sends a POST request to the callback URL with file information (bucket, object, size, ETag) and custom parameters.
-
The server processes the callback and responds
Your server receives the callback, optionally verifies the request signature, and must return a JSON response within 5 seconds. HTTP 200 indicates success; any other status code means failure.
-
OSS returns the upload result
OSS forwards the server's response body back to the client as the upload result.
Implementation
Implement and test the client side and server side separately, then run an end-to-end integration test.
Client-side implementation
These sections cover callback parameter construction. For a quicker start, use the SDK examples below.
Include the callback parameter and the optional callback-var parameter in your upload request.
-
Construct the callback parameter
This parameter is a Base64-encoded JSON object that defines the application server URL and the request body format.
-
Basic configuration example:
{ "callbackUrl":"http://oss-demo.aliyuncs.com:23450", "callbackBody":"bucket=${bucket}&object=${object}&my_var=${x:my_var}" }In this example:
-
callbackUrl: The URL of the application server. You must change this to your actual URL. For example:
http://oss-demo.aliyuncs.com:23450. -
callbackBody: The callback request body content. Use placeholders such as
${bucket}for the bucket name,${object}for the full file path, and${x:xxx}for custom variables. OSS replaces placeholders with actual values during the callback. Supported placeholders are listed in System parameters for callbackBody.
-
-
Advanced configuration example:
{ "callbackUrl":"http://oss-demo.aliyuncs.com:23450", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"bucket=${bucket}&object=${object}&my_var=${x:my_var}", "callbackBodyType":"application/x-www-form-urlencoded", "callbackSNI":false }Each field is described in Callback parameters.
-
-
Construct the optional callback-var parameter
ImportantThe
callback-varparameter must be in JSON format. The key for each custom parameter must start with x: and can contain only lowercase letters, for example,x:uid.Use this parameter to pass custom information to your application server, such as a user ID or order number:
{ "x:uid": "12345", "x:order_id": "67890" }The
callback-varparameter works withcallbackBody. Reference custom variables using the${x:xxx}placeholder incallbackBody:{ "callbackUrl": "http://oss-demo.aliyuncs.com:23450", "callbackBody": "uid=${x:uid}&order=${x:order_id}" }When the callback is triggered, OSS sends the following content, assuming
callbackBodyTypeisapplication/x-www-form-urlencoded:uid=12345&order=67890 -
Base64-encode the callback and callback-var parameters
-
Example: Encode the callback parameter
Original
callbackparameter:{ "callbackUrl": "http://oss-demo.aliyuncs.com:23450", "callbackHost": "your.callback.com", "callbackBody": "bucket=${bucket}&object=${object}&uid=${x:uid}&order=${x:order_id}", "callbackBodyType": "application/x-www-form-urlencoded", "callbackSNI": false }Base64-encoded result:
eyJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLCAiY2FsbGJhY2tVcmwiOiAiaHR0cDovL29zcy1kZW1vLmFsaXl1bmNzLmNvbToyMzQ1MCIsICJjYWxsYmFja0JvZHkiOiAiYnVja2V0PSR7YnVja2V0fSZvYmplY3Q9JHtvYmplY3R9JnVpZD0ke3g6dWlkfSZvcmRlcj0ke3g6b3JkZXJfaWR9IiwgImNhbGxiYWNrQm9keVR5cGUiOiAiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwgImNhbGxiYWNrU05JIjogZmFsc2V9 -
Example: Encode the callback-var parameter
Original
callback-varparameter:{ "x:uid": "12345", "x:order_id": "67890" }Base64-encoded result:
eyJ4OnVpZCI6ICIxMjM0NSIsICJ4Om9yZGVyX2lkIjogIjY3ODkwIn0=
-
-
Attach the encoded parameters to your request
After encoding the parameters, you can pass them to OSS in one of the following ways.
Header (recommended)
Recommended for SDK or backend uploads. Pass callback parameters in the
x-oss-callbackandx-oss-callback-varHTTP headers:-
x-oss-callback: The Base64-encodedcallbackparameter. -
x-oss-callback-var(optional): The Base64-encodedcallback-varparameter.
Note: You must include these two headers in the canonical headers when calculating the request signature.
Example: Pass callback parameters in the header
PUT /your_object HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-Encoding: identity Content-Length: 5 x-oss-callback-var: eyJ4OnVpZCI6ICIxMjM0NSIsICJ4Om9yZGVyX2lkIjogIjY3ODkwIn0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLCAiY2FsbGJhY2tVcmwiOiAiaHR0cDovL29zcy1kZW1vLmFsaXl1bmNzLmNvbToyMzQ1MCIsICJjYWxsYmFja0JvZHkiOiAiYnVja2V0PSR7YnVja2V0fSZvYmplY3Q9JHtvYmplY3R9JnVpZD0ke3g6dWlkfSZvcmRlcj0ke3g6b3JkZXJfaWR9IiwgImNhbGxiYWNrQm9keVR5cGUiOiAiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwgImNhbGxiYWNrU05JIjogZmFsc2V9 Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Wed, 26 Apr 2023 03:46:17 GMT Content-Type: text/plain Authorization: OSS qn6q**************:77Dv**************** TestPOST body
This method applies only to uploads that use the PostObject API operation. Callback parameters must be passed as form fields in the body of the POST request.
-
Callback parameter: Pass the Base64-encoded JSON configuration as a separate form field.
--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLCAiY2FsbGJhY2tVcmwiOiAiaHR0cDovL29zcy1kZW1vLmFsaXl1bmNzLmNvbToyMzQ1MCIsICJjYWxsYmFja0JvZHkiOiAiYnVja2V0PSR7YnVja2V0fSZvYmplY3Q9JHtvYmplY3R9JnVpZD0ke3g6dWlkfSZvcmRlcj0ke3g6b3JkZXJfaWR9IiwgImNhbGxiYWNrQm9keVR5cGUiOiAiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwgImNhbGxiYWNrU05JIjogZmFsc2V9 -
Callback-var parameter (custom variables): Each custom parameter must be passed as a separate form field; you cannot combine them in a single
callback-varfield.For example, consider the custom variables
uidandorder_id:{ "x:uid": "12345", "x:order_id": "67890" }You must convert them into two separate form fields.
--9431149156168 Content-Disposition: form-data; name="x:uid" 12345 --9431149156168 Content-Disposition: form-data; name="x:order_id" 67890 -
Validate the callback parameter (optional): You can specify conditions in the policy to validate the
callbackparameter. If no conditions are set, the parameter is not validated during the upload. For example:{ "expiration": "2021-12-01T12:00:00.000Z", "conditions": [ {"bucket": "examplebucket" }, {"callback": "eyJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLCAiY2FsbGJhY2tVcmwiOiAiaHR0cDovL29zcy1kZW1vLmFsaXl1bmNzLmNvbToyMzQ1MCIsICJjYWxsYmFja0JvZHkiOiAiYnVja2V0PSR7YnVja2V0fSZvYmplY3Q9JHtvYmplY3R9JnVpZD0ke3g6dWlkfSZvcmRlcj0ke3g6b3JkZXJfaWR9IiwgImNhbGxiYWNrQm9keVR5cGUiOiAiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwgImNhbGxiYWNrU05JIjogZmFsc2V9"}, ["starts-with", "$key", "user/eric/"] ] }
URL
-
Used for uploading files with a presigned URL. Triggers the callback by appending Base64-encoded callback parameters to the URL. This exposes callback information in the URL, so use it only for temporary access or low-sensitivity scenarios.
-
If you pass callback parameters in the URL, include the
callbackparameter (required) and optionallycallback-var. Both must be part of the Canonical Query String for signature calculation. Signature Version 4.Example:
PUT /your_object?OSSAccessKeyId=LTAI******************&Signature=vjby*************************************&Expires=1682484377&callback-var=eyJ4OnVpZCI6ICIxMjM0NSIsICJ4Om9yZGVyX2lkIjogIjY3ODkwIn0=&callback=eyJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLCAiY2FsbGJhY2tVcmwiOiAiaHR0cDovL29zcy1kZW1vLmFsaXl1bmNzLmNvbToyMzQ1MCIsICJjYWxsYmFja0JvZHkiOiAiYnVja2V0PSR7YnVja2V0fSZvYmplY3Q9JHtvYmplY3R9JnVpZD0ke3g6dWlkfSZvcmRlcj0ke3g6b3JkZXJfaWR9IiwgImNhbGxiYWNrQm9keVR5cGUiOiAiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwgImNhbGxiYWNrU05JIjogZmFsc2V9 HTTP/1.1 Host: callback-test.oss-cn-hangzhou.aliyuncs.com Date: Wed, 26 Apr 2023 03:46:17 GMT Content-Length: 5 Content-Type: text/plain
-
Server-side implementation
For code examples in different languages, see Server-side code examples.
Your application server must:
-
Receive POST requests from OSS
After a successful upload, OSS sends a POST request to your callback URL:
POST /test HTTP/1.1 Host: your.callback.com Connection: close Authorization: GevnM3**********3j7AKluzWnubHSVWI4dY3VsIfUHYWnyw== Content-MD5: iKU/O/JB***ZMd8Ftg== Content-Type: application/x-www-form-urlencoded Date: Tue, 07 May 2024 03:06:13 GMT User-Agent: aliyun-oss-callback x-oss-bucket: your_bucket x-oss-pub-key-url: aHR0cHM6Ly9nb3NzcHVi**********vY2FsbGJeV92MS5wZW0= x-oss-request-id: 66399AA50*****3334673EC2 x-oss-requester: 23313******948342006 x-oss-signature-version: 1.0 x-oss-tag: CALLBACK bucket=your_bucket&object=your_object&uid=12345&order_id=67890 -
Verify the request signature for security (optional)
To confirm the request is from OSS, verify its signature on your application server. See Recommended configurations.
NoteSignature verification is optional.
-
Return a callback response
Your application server must return a response to OSS that meets the following requirements:
-
The application server must return
HTTP/1.1 200 OK. -
The response header must include
Content-Length. -
The response body supports JSON or XML format. The example in this topic uses JSON. For XML, add
Content-Type: application/xmlto the response header.
For example, the application server can return {"Status": "OK"}.
Note: This example uses Python 2.7.6. We recommend using Python 3 for new development.
HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"Status": "OK"}OSS then forwards this response body to the client. The following code shows an example:
HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"Status": "OK"}ImportantFor a
CompleteMultipartUploadrequest, if the original response body contains content (for example, information in JSON format), this content is overwritten by the response from the upload callback after the feature is enabled, for example, by{"Status": "OK"}. -
Recommended configurations
Verify the request signature
OSS sends a POST request to your callbackUrl after an upload. Verify the request signature to confirm it originates from OSS.
-
How OSS signs the callback request
OSS signs the request using RSA with an MD5 hash and places the Base64-encoded signature in the
authorizationheader.-
The signature is calculated as follows:
authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + '\n' + body, md5))NoteIn this formula,
private_keyis the private key,pathis the resource path of the callback request,query_stringis the query string, andbodyis the callback body. -
The steps to generate the signature are:
-
Construct the string to sign by concatenating the URL-decoded resource path, the original query string, a newline character, and the callback body.
-
RSA-sign the string: Use the key to sign the string. The hash function for the signature is MD5.
-
Base64-encode the signed result to obtain the final signature, and then place the signature in the
authorizationheader of the callback request.
-
-
Example of signature generation:
POST /index.php?id=1&index=2 HTTP/1.0 Host: 172.16.XX.XX Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZj****/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2t**** Content-Type: application/x-www-form-urlencoded User-Agent: http-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnsr**** bucket=examplebucketThe path is
/index.php, the query_string is?id=1&index=2, the body isbucket=examplebucket, and the final signature result iskKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2t****.
-
-
How your server verifies the signature
Verify the request signature to confirm authenticity:
-
Get the public key:
Get and Base64-decode the public key URL from the
x-oss-pub-key-urlrequest header.public_key = urlopen(base64_decode(value of x-oss-pub-key-url header))Example value before decoding:
aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==After decoding:
http://gosspublic.alicdn.com/callback_pub_key_v1.pemNoteThe public key URL must start with
http://gosspublic.alicdn.com/orhttps://gosspublic.alicdn.com/. Cache the public key locally to avoid disruptions from network issues. -
Decode the signature.
Get and Base64-decode the signature from the
authorizationrequest header:signature = base64_decode(value of authorization header) -
Construct the string to verify.
Concatenate the resource path, query string, a newline character, and the callback body in the following format:
sign_str = url_decode(path) + query_string + ‘\n’ + body -
Verify the signature.
Use an MD5 hash with the RSA public key for verification:
result = rsa_verify(public_key, md5(sign_str), signature)
-
-
Example of signature verification
The following Python 3 example shows how to verify a signature in an application server. This example requires the
M2Cryptolibrary.import http.client import base64 import hashlib import urllib.request import urllib.parse import socket from http.server import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): # Get the public key. pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = base64.b64decode(pub_key_url_base64).decode() if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib.request.urlopen(pub_key_url) # We recommend that you cache the public key content based on the public key URL to improve performance. pub_key = url_reader.read() except Exception as e: print('pub_key_url : ' + pub_key_url) print('Get pub key failed! Error:', str(e)) self.send_response(400) self.end_headers() return # Get the signature. authorization_base64 = self.headers['authorization'] authorization = base64.b64decode(authorization_base64) # Get the callback body. content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) # Compose the string for signature verification. auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib.parse.unquote(self.path) + '\n' + callback_body.decode() else: auth_str = urllib.parse.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body.decode() print(auth_str) # Verify the signature. auth_md5 = hashlib.md5(auth_str.encode()).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print('Authorization verify failed!') print('Public key : %s' % (pub_key)) print('Auth string : %s' % (auth_str)) self.send_response(400) self.end_headers() return # Process the request based on the callback body. # Respond to OSS. resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body.encode()) class MyHTTPServer(HTTPServer): def __init__(self, host, port): super().__init__((host, port), MyHTTPRequestHandler) if __name__ == '__main__': server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()The following table lists the server-side code for other languages.
Language
Description
Java
-
Download URL: Java
-
To run the application, unzip the package and run the command
java -jar oss-callback-server-demo.jar 9000(9000 is the port number, which you can change).
Python
-
Download URL: Python
-
Unzip the package and run
python callback_app_server.py. This program requires the installation of RSA dependencies.
PHP
-
Download URL: PHP
-
Deploy in an Apache environment. Some data headers vary by environment—adjust the code accordingly.
.NET
-
Download URL: .NET
-
To run: Unzip the package and refer to
README.md.
Node.js
-
Download URL: Node.js
-
To run, unzip the package and run
node example.js.
Ruby
-
Download URL: Ruby
-
How to run:
ruby aliyun_oss_callback_server.rb
-
Callback parameters
The following table describes the callback parameters that configure the callback request OSS sends after a successful upload.
|
Field |
Required |
Description |
|
callbackUrl |
Yes |
The URL where OSS sends a POST request after a successful file upload.
|
|
callbackBody |
Yes |
The content of the callback request body. The format must match the value of the
|
|
callbackHost |
No |
The value of the Host header in the callback request. The value can be a domain name or an IP address.
|
|
callbackSNI |
No |
Specifies whether to include Server Name Indication (SNI) in the callback request. SNI is used in an HTTPS request to identify the domain name and return the correct certificate. If
|
|
callbackBodyType |
No |
The Content-Type of the callback request, which is the data format of the The following types are supported:
|
System parameters for callbackBody
The callbackBody field supports the following system parameters for passing uploaded file information in the callback request.
|
Parameter |
Description |
|
bucket |
The name of the bucket. |
|
object |
The full path of the object (file). |
|
etag |
The ETag of the file. This is the same ETag value returned to the user. |
|
size |
The object size. For a |
|
mimeType |
The resource type. For example, the resource type of a JPEG image is |
|
imageInfo.height |
The height of the image. Empty for non-image files. |
|
imageInfo.width |
The width of the image. Empty for non-image files. |
|
imageInfo.format |
The image format (JPG, PNG, etc.). Empty for non-image files. |
|
crc64 |
This value is the same as the value of the |
|
contentMd5 |
This value is the same as the value of the Important
This variable is not empty only when you upload a file by using the |
|
vpcId |
The VPC ID of the requesting client. This variable is empty if the request did not originate from a VPC. |
|
clientIp |
The IP address of the client that initiated the request. |
|
reqId |
The request ID. |
|
operation |
The name of the API operation that was called, such as |
SDK
Client-side callback implementation demos:
|
Simple upload (uses the PutObject API operation) |
Multipart upload (uses the CompleteMultipartUpload API operation) |
Upload by using a presigned URL (uses the PutObject API operation) |
|
|
Java |
|||
|
Python V2 |
- |
||
|
Go V2 |
Troubleshooting
OSS error messages include an EC code for troubleshooting. Callback-related EC codes are listed in 07-CALLBACK.
FAQ
Callback on upload failure
No. Callbacks are triggered only for successful uploads. For failed uploads, OSS returns an error directly to the client instead of triggering a callback.
Invalid JSON format error
-
An exception on the application server causes it to return a response body that is not in a valid JSON format. The following figure provides an example.

Solution:
-
Run the following command to confirm the content.
curl -d "<Content>" <CallbackServerURL> -v -
Capture packets to confirm the content.
On Windows, we recommend using Wireshark to capture packets. On Linux, run the tcpdump command.
-
-
The body that the application server returns to OSS contains a byte order mark (BOM).
This error is common in PHP applications. The PHP SDK can return a byte order mark (BOM), which adds three extra bytes to the response body and invalidates the JSON format. As shown in the following figure, the three bytes
ef bb bfare the BOM.
Solution: Remove the BOM from the application server's response body.