Performs a callback by sending a request that contains callback parameters to Object Storage Service (OSS). This topic describes how to configure callbacks.
Usage notes
You can configure callbacks in the following regions: 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, Australia (Sydney), Malaysia (Kuala Lumpur), Indonesia (Jakarta), Philippines (Manila), India (Mumbai), Germany (Frankfurt), UK (London), and UAE (Dubai).
Only the PutObject, PostObject, and CompleteMultipartUpload operations support callbacks.
The default timeout period for a callback request is 5 seconds.
If a callback request fails, the callback request is not retried.
Callbacks are not supported if server name indication (SNI) is used.
Step 1: Construct a callback parameter
Callback parameter
The callback parameter is a Base64-encoded string that contains multiple fields in the JSON format. To construct a callback parameter, you must specify the URL (callbackUrl) of the server to which OSS sends a callback request and the content (callbackBody) of the callback request.
The following table describes the fields in the JSON format.
Field
Required
Description
callbackUrl
Yes
The URL of the server to which OSS sends a callback request.
After you upload an object, OSS uses the POST method to send a callback request to the URL. The body of the request is the content that is specified by the callbackBody field. In most cases, the server whose URL is used returns the
HTTP/1.1 200 OK
response. The response body must be in the JSON format, and the value of the Content-Length response header must be valid and less than or equal to 3 MB in size.You can specify up to five URLs in a callback request. Separate the URLs with semicolons (;). OSS sends callback requests to each URL until a success response is returned.
HTTPS URLs are supported.
To ensure that Chinese characters can be correctly processed, you must encode the callback URL.
callbackHost
No
The value of the Host header in the callback request. The value must be in the format of a domain name or an IP address.
This field takes effect only if you configure the callbackUrl field.
If you do not configure the callbackHost field, the host values are resolved from the URLs of the callbackUrl field and are specified as the value of the callbackHost field.
callbackBody
Yes
The value of the callback request body. Example:
key=${object}&etag=${etag}&my_var=${x:my_var}
.The callbackBody field supports OSS system parameters, custom parameters, and constants.
In the PutObject and CompleteMultipart operations, custom parameters are passed through the callback-var parameter.
In the PostObject operation, variables are passed through the form field.
callbackBodyType
No
The value of the Content-Type header in the callback request. Valid values:
application/x-www-form-urlencoded (default)
If you set the callbackBodyType field to application/x-www-form-urlencoded, the variables in the callbackBody field are replaced by URL-encoded values.
application/json
If you set the callbackBodyType field to application/json, the variables in the callbackBody field are replaced by values in the JSON format.
Examples of the JSON fields:
Example 1 (includes required and optional fields)
{ "callbackUrl":"172.16.XX.XX/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" }
Example 2 (includes only required fields)
{ "callbackUrl":"172.16.XX.XX:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" }
You can configure system parameters for the callbackBody field. The following table describes the parameters.
System parameter
Description
bucket
The name of the bucket.
object
The full path of the object.
etag
The ETag field that is configured for the object and returned to the requester.
size
The size of the object. The size is the total size of the object when you call the CompleteMultipartUpload operation.
mimeType
The resource type. For example, the resource type of JPEG images is image/jpeg.
imageInfo.height
The height of the image. This parameter applies only to image objects. For other objects, this parameter is left empty.
imageInfo.width
The width of the image. This parameter applies only to image objects. For other objects, this parameter is left empty.
imageInfo.format
The format of the image. Examples: JPG and PNG. This parameter applies only to image objects. For other objects, this parameter is left empty.
crc64
The value of this parameter is the same as that of the x-oss-hash-crc64ecma header returned after the object is uploaded.
contentMd5
The value of this parameter is the same as that of the Content-MD5 header returned after the object is uploaded.
ImportantThis parameter is required only if you call the PutObject or PostObject operation to upload an object.
vpcId
The ID of the virtual private cloud (VPC) in which the client that initiates the request resides. If the request is not initiated by using a VPC, this parameter is left empty.
clientIp
The IP address of the client that initiates the request.
reqId
The request ID that is used to initiate the request.
operation
The API operation that is used to initiate the request, such as PutObject and PostObject.
Custom parameters
You can configure custom parameters by using the callback-var parameter. Custom parameters are key-value pairs. When a POST callback request is initiated, OSS adds the custom parameters and system parameters in the preceding table to the body of the POST request. This way, the requester can obtain these parameters.
You can create a custom parameter in the same manner that you create a callback parameter. Specify the custom parameters in the JSON format. The JSON string consists of key-value pairs of all custom parameters.
ImportantThe key of a custom parameter must start with
x:
and must be in lowercase letters. Otherwise, the system cannot assign a valid value to the custom parameter regardless of whether HTTP status code 200 is returned.For example, you configure two custom parameters named
x:var1
andx:var2
. The value of x:var1 is value1, and the value of x:var2 is value2. The following JSON string is created:{ "x:var1":"value1", "x:var2":"value2" }
Step 2: Configure a callback request
To add the callback and callback-var parameters to a request that you want OSS to send, you must use Base64 to encode the JSON strings that you created in the preceding step, and then add the parameters to the request by using one of the following methods:
Add the parameters to the URL
If you add the parameters to the URL, the callback
parameter is required and the callback-var
parameter is optional. If a request contains the callback
or callback-var
parameter, you must use the callback or callback-var parameter as a subresource of CanonicalizedResource when you calculate the signature. For more information, see Include signatures in the Authorization header.
PUT /test.txt?OSSAccessKeyId=LTAI5t7h6SgiLSga****&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv****&Expires=1682484377&callback-var=eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0****&callback=eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9**** 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
Add the parameters to the request as a header
Add the x-oss-callback
or x-oss-callback-var
header to the request. The x-oss-callback-var and x-oss-callback headers are included in CanonicalizedOSSHeaders to calculate the signature. Example:
PUT /test.txt HTTP/1.1
Host: callback-test.oss-test.aliyun-inc.com
Accept-Encoding: identity
Content-Length: 5
x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0****
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: eyJjYWxsYmFja1****4x
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 mlepou3zr4u****:5a74vhd4UXpmyuudV14Kaen5****
Test
Add the parameters to the form fields in the body of a POST request
You can use only this method to configure callback parameters when you upload objects by calling the PostObject operation.
If you want to add the callback parameter when you use the POST method to upload an object, add the callback parameter by using a different form field. Example:
--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLj****4xN
Each custom parameter uses a different form field. You cannot add the callback-var parameter to existing form fields. You must add each custom parameter by using a separate form field. Example of JSON fields that you can configure for custom parameters:
{ "x:var1":"value1", "x:var2":"value2" }
Example of form fields in the POST request:
--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLj****4xN --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2
You can add callback conditions to the policy. If you do not add callback conditions to the policy, the callback parameters are not verified for the upload. Example:
{ "expiration": "2021-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1V****4My"}, ["starts-with", "$key", "user/eric/"], ] }
Step 3: Initiate a callback request
If you upload an object, OSS sends the content that you specified for the callback and callback-var parameters in the request to the application server by using the POST method. Example:
POST /index.html HTTP/1.0
Host: 172.16.XX.XX
Connection: close
Content-Length: 181
Content-Type: application/x-www-form-urlencoded
User-Agent: http-client/0.0.1
bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test
Step 4 (optional): Sign the callback request
If you configure the callback parameter in the request, OSS uses the POST method to send a callback request to the application server based on the specified callback URL. To check whether the callback request that is received by the application server is initiated by OSS, you can sign the callback request.
Step 1: Generate a signature
Method for generating a signature
OSS uses the RSA encryption algorithm to sign a callback request.
authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + '\n' + body, md5))
NoteIn the preceding code, private_key specifies a private key, path specifies the resource path that is included in the callback request, query_string specifies the query string, and body specifies the message body in the callback request.
Procedure for generating a signature
Obtain the callback string that you want to sign. The string consists of the resource path that is obtained by decoding the URL, the original query string, a carriage return, and the callback message body.
Sign the callback string by using the RSA encryption algorithm. Use the private key to encrypt the signature string. The hash function that is used for the signature is MD5.
Use Base64 to encode the signed result to obtain the final signature. Then, add the signature to the Authorization header in the callback request.
Example
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=examplebucket
In the preceding code, path is set to
/index.php
, query_string is set to?id=1&index=2
, and the body is set tobucket=examplebucket
. The final signature iskKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2t****
.
Step 2: Verify the signature
Method for verifying the signature
The following sample code provides an example on how to verify the signature by using the application server:
Result = rsa_verify(public_key, md5(url_decode(path) + query_string + '\n' + body), base64_decode(authorization))
public_key specifies the public key, and authorization specifies the signature that you want to include in the callback request header.
Procedure for verifying the signature
The
x-oss-pub-key-url
header in the callback request stores the Base64-encoded URL of the public key. Decode the Base64-encoded URL to obtain the public key.public_key = urlopen(base64_decode(x-oss-pub-key-url header value))
For example, obtain the URL of the public key by decoding
aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==
in Base64. The decoded URL ishttp://gosspublic.alicdn.com/callback_pub_key_v1.pem
.NoteThe value of the
x-oss-pub-key-url
header in the public_key field issued by OSS must start withhttp://gosspublic.alicdn.com/
orhttps://gosspublic.alicdn.com/
.Obtain the signature that is decoded in Base64.
signature = base64_decode(authorization header value)
Obtain the string to sign by performing the same procedure that you use to obtain the string after the callback request is signed.
sign_str = url_decode(path) + query_string + '\n' + body
Verify the signature.
result = rsa_verify(public_key, md5(sign_str), signature)
Example
The following code provides an example on how an application server verifies a signature. Before you run the code in OSS SDK for Python, install the M2Crypto library.
import httplib import base64 import md5 import urllib2 from BaseHTTPServer 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 public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') 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 = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).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 #do something according to callback_body #response 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) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()
The following table describes the code that you can use to verify a signature on the server in other programming languages.
SDK programming language
Description
Java
Download link: OSS SDK for Java
Running method: Decompress the package and run
java -jar oss-callback-server-demo.jar 9000
. The port number is 9000. You can change the port number.
Python
Download link: OSS SDK for Python
Running method: Decompress the package and run
python callback_app_server.py
. Before you run the code, install RSA dependencies.
Go
Download link: OSS SDK for Go
Running method: Decompress the package and follow the instructions in README.md.
PHP
Download link: OSS SDK for PHP
Running method: Deploy the code to an Apache environment to ensure that specific headers in the code can use the environment as a dependency. You can modify the sample code based on the environment.
.NET
Download link: OSS SDK for .NET
Running method: Decompress the package and follow the instructions in
README.md
.
Node.js
Download link: OSS SDK for Node.js
Running method: Decompress the package and run
node example.js
.
Ruby
Download link: OSS SDK for Ruby
Running method: Run ruby aliyun_oss_callback_server.rb.
Step 5: Return the callback result
The application server returns a response to OSS. The following example shows a response that is returned for a callback request:
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
{"a":"b"}
The response that is returned by the application server to OSS must contain the Content-Length header. The size of the response body cannot exceed 1 MB.
Step 6: Return the upload result
OSS returns the information that is returned by the application server to the requester.
The following example shows a returned response:
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
{"a":"b"}
The response bodies of CompleteMultipartUpload
requests contain content such as data in the XML format. If you use the upload callback feature, the original body content such as {"a":"b"}
is overwritten.
Error codes
Error code | HTTP status code | Description |
InvalidArgument | 400 | The value of the callback or callback-var parameter is invalid due to one of the following reasons:
|
CallbackFailed | 203 | The object is uploaded to OSS, but the callback fails. A callback failure indicates that OSS does not receive the expected callback response. The failure does not indicate that the application server does not receive a callback request. For example, if the response that is returned by the application server is not in the JSON format, a callback failure occurs. |
FAQ
Does OSS send a callback request to the application server when an object fails to be uploaded?
No. OSS sends a callback request to the application server only if an object is uploaded. If the object fails to be uploaded, OSS does not send a callback request to the application server but returns an error message to the application server.
What do I do if the "Response body is not valid json format" error message is returned?
The error message is returned because the application server throws an exception when the request is being processed. In this case, the response body that is returned to OSS is not in the JSON format. The following figure shows the response that is returned to OSS when this error occurs.
Solution:
Run the following command to confirm the content:
curl -d "<Content>" <CallbackServerURL> -v
Capture packets to confirm the content.
We recommend that you use the Wireshark tool in Windows or run the tcpdump command in Linux to capture packets.
The error occurs because the response body that is returned by the application server to OSS includes a BOM header.
This error is common among application servers that are written by using OSS SDK for PHP. OSS SDK for PHP returns the BOM header. As a result, OSS receives three additional bytes in the response body that is not in the JSON format. The following figure shows that the ef, bb, and bf bytes are the additional bytes in the response body.
Solution: Delete the BOM header from the response body that is returned by the application server to OSS.