All Products
Search
Document Center

Object Storage Service:Callback

Last Updated:Apr 28, 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

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

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. For example, you must encode http://example.com /Chinese.php?key=value&Chinese name=Chinese 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 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}&x: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.

    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 except the UK (London) region, the SNI is sent based on the callbackSNI value.

    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}&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 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.

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

    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.

    For example, you configure two custom parameters named x:var1 and x: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 Creation of CanonicalizedResource.

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

Note

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

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

  • Procedure for generating a signature

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

    2. Sign the callback string by using the RSA encryption algorithm and use the private key to encrypt the signature string. The hash function that is used for 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, path is set to /index.php, query_string is set to ?id=1&index=2, and the body is set to bucket=examplebucket. The final signature is kKQeGTRccDKyHB3H9vF+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

    1. 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 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 signature that is decoded in Base64.

      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 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 specify a different 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"}
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 due to 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 valid 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 variables in the callbackBody field that you decoded from the callback parameter are not in the ${var} format.

  • The variables 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. 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.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 callback 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.