All Products
Search
Document Center

Object Storage Service:Callback

Last Updated:Jul 17, 2024

To configure upload callbacks, you need to only add the related callback parameters to the upload request that is sent to OSS. This topic describes how to configure callbacks.

Usage notes

  • Callbacks are supported 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) Closing Down, 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.

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 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. You must separate 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. For example, you must encode http://example.com/中文.php?key=value&中文名称=中文值 into http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC.

    callbackHost

    No

    The value of the Host header in the callback request. The value must be 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 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, parameters are passed by using form fields.

    callbackSNI

    No

    Specifies whether OSS sends Server Name Indication (SNI) to the origin address specified by callbackUrl when a callback request is initiated from the client. Whether OSS sends SNI depends on the server configurations and region requirements. SNI is recommended for servers that use the same IP address to host multiple TLS/SSL certificates. Valid values:

    • true

    • false (default)

      Note

      When a callback request is initiated in the UK (London) region, the SNI is sent regardless of the callbackSNI value. When a callback request is initiated in a region other than the UK (London) region, whether the SNI is sent depends on the callbackSNI field value.

    callbackBodyType

    No

    The content type of the callback request. Valid values:

    • application/x-www-form-urlencoded (default)

      If you set the callbackBodyType field to application/x-www-form-urlencoded, the parameters in the callbackBody field are replaced by URL-encoded values.

    • application/json

      If you set the callbackBodyType field to application/json, the parameters in the callbackBody field are replaced by values in the JSON format.

    JSON field examples

    • 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",
      "callbackSNI":false
      }
    • 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}&x: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 of the object. The ETag is returned to the requester.

    size

    The size of the object. The size is the size of the entire 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 CRC64 value. 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 MD5 value. The value of this parameter is the same as that of the Content-MD5 header returned after the object is uploaded.

    Important

    This 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 over a VPC, this parameter is left empty.

    clientIp

    The IP address of the client that initiates the request.

    reqId

    The ID of the request that is initiated.

    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. A custom parameter is a key-value pair, such as my_var=${x:my_var}. 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. You must specify custom parameters in the JSON format. The JSON string consists of key-value pairs of all custom parameters.

    Important

    The 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.

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:

  • Construct the callback (x-oss-callback) parameter

    1. Specify fields that are used to construct the parameter.

      {
          "callbackUrl": "http://xxx.xxx.22.143/test",
          "callbackHost": "your.callback.com",
          "callbackBody": "bucket=${bucket}&object=${object}&my_var=${x:my_var}",
          "callbackBodyType": "application/x-www-form-urlencoded",
          "callbackSNI": false
      }
    2. Encode the preceding fields in Base64.

      ewogICAg****bGxiYWNrVXJsIjogImh0dHA6Ly94eHgueHh4LjIyLjE0My90ZXN0IiwKICAgICJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLAogICAgImNhbGxiYWNrQm9keSI6ICJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyPSR7eDpteV92YXJ9IiwKICAgICJjYWxsYmFja0JvZHlUeXBlIjogImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsCiAgICAiY2FsbGJhY2tTTkkiOiBmYWxzZQp9
  • Construct the callback-var (x-oss-callback-var) parameter.

    1. Specify fields that are used to construct the parameter.

      {"x:my_var": "var"}
    2. Encode the preceding field in Base64.

      eyJ4Om15X3ZhciI6ICJ2YX****==

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 Creation of CanonicalizedResource.

PUT /your_object?OSSAccessKeyId=LTAI5t7h6SgiLSga****&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv****&Expires=1682484377&callback-var=eyJ4Om15X3ZhciI6ICJ2YX****==&callback=bGxiYWNrVXJsIjogImh0dHA6Ly94eHgueHh4LjIyLjE0My90ZXN0IiwKICAgICJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLAogICAgImNhbGxiYWNrQm9keSI6ICJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyPSR7eDpteV92YXJ9IiwKICAgICJjYWxsYmFja0JvZHlUeXBlIjogImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsCiAgICAiY2FsbGJhY2tTTkkiOiBmYWxzZQp9 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 /your_object HTTP/1.1
Host: callback-test.oss-test.aliyun-inc.com
Accept-Encoding: identity
Content-Length: 5
x-oss-callback-var: eyJ4Om15X3ZhciI6ICJ2YX****==
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: ewogICAg****bGxiYWNrVXJsIjogImh0dHA6Ly94eHgueHh4LjIyLjE0My90ZXN0IiwKICAgICJjYWxsYmFja0hvc3QiOiAieW91ci5jYWxsYmFjay5jb20iLAogICAgImNhbGxiYWNrQm9keSI6ICJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyPSR7eDpteV92YXJ9IiwKICAgICJjYWxsYmFja0JvZHlUeXBlIjogImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsCiAgICAiY2FsbGJhY2tTTkkiOiBmYWxzZQp9
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****************
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 separate form field. Example:

    --9431149156168
    Content-Disposition: form-data; name="callback"
    eyJjYWxsYmFja1VybCI6IjEwLj****4xN
  • If you want to add the callback-var parameter to a POST request, you cannot directly add the parameter as a whole. Instead, you must add each custom parameter by using a separate form field. Example:

    {
    "x:var1":"value1",
    "x:var2":"value2"
    }

    The following content provides an example on how to add the preceding custom parameters:

    --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 the object upload is successful, 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 /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&my_var=var

(Optional) Step 4: 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.

Note

Signature verification is optional. You can specify whether to perform signature verification based on your business requirements.

Step 1: Generate a signature

  • Signature generation algorithm

    OSS uses the RSA encryption algorithm to calculate a signature.

    authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + '\n' + body, md5))
    Note

    In 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.

  • Signature generation method

    1. Create the string 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.

    2. Sign the created string by using the RSA encryption algorithm and the private key. The hash function that is used to calculate the signature is MD5.

    3. 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, the final signature is kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2t****. The signature is generated from the /index.php path, the ?id=1&index=2 query string, and bucket=examplebucket body.

Step 2: Verify the signature

  • Signature verification method

    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.

  • Signature verification process

    1. The x-oss-pub-key-url header in the callback request stores the Base64-encoded URL of the public key. You must 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 is http://gosspublic.alicdn.com/callback_pub_key_v1.pem.

      Note

      The value of the x-oss-pub-key-url header in the public_key field issued by OSS must start with http://gosspublic.alicdn.com/ or https://gosspublic.alicdn.com/.

    2. Obtain the Base64-decoded form of the signature.

      signature = base64_decode(authorization header value)
    3. 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
    4. Verify the signature.

      result = rsa_verify(public_key, md5(sign_str), signature)
  • Example

    The following Python code provides an example on how an application server verifies a signature. The M2Crypto library is required to run the sample code.

    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: Java code sample

    • Running method: Decompress the package and run java -jar oss-callback-server-demo.jar 9000. You can replace port number 9000 with a different port number.

    Python

    • Download link: Python code sample

    • Running method: Decompress the package and run python callback_app_server.py. The RSA dependencies are required to run the code sample.

    Go

    • Download link: Go sample code sample

    • Running method: Decompress the package and follow the instructions in README.md.

    PHP

    • Download link: PHP code sample

    • 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: .NET code sample

    • Running method: Decompress the package and follow the instructions in README.md.

    Node.js

    • Download link: Node.js code sample

    • Running method: Decompress the package and run node example.js.

    Ruby

    • Download link: Ruby code sample

    • 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"}
Note

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"}
Important

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 for one of the following reasons:

  • You specified URLs and headers for the callback (x-oss-callback) or callback-var parameter (x-oss-callback-var) in the PutObject and CompleteMultipartUpload operations.

  • The length of the callback or callback-var parameter exceeds 5 KB.

  • The callback or callback-var parameter is not Base64-encoded, or the parameter is not in the JSON format after you decode the parameter.

  • The callbackUrl field that you decoded from the callback parameter includes more than five URLs or the port in the URL is invalid. Example:

    {"callbackUrl":"172.16.XX.XX:test",
        "callbackBody":"test"}
  • The callbackBody field that you decoded from the callback parameter is empty.

  • The value of the callbackBodyType field that you decoded from the callback parameter is not application/x-www-form-urlencoded or application/json.

  • The parameters in the callbackBody field that you decoded from the callback parameter are not in the ${var} format.

  • The parameters that you decoded from the callback-var parameter are not in the following JSON format: {"x:var1":"value1","x:var2":"value2"...}.

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, and 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 does not send a callback request to the application server when an object fails to be uploaded. 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.

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.callback

    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 body of the response 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.

    callback1

    Solution: Delete the BOM header from the response body that is returned by the application server to OSS.