All Products
Search
Document Center

Object Storage Service:Upload callbacks

Last Updated:May 29, 2025

After an object is uploaded, Object Storage Service (OSS) can send a callback request to the application server. To implement a callback, you need to only send a request that contains relevant callback parameters to OSS.

Usage notes

  • In this topic, the public endpoint of the China (Hangzhou) region is used. To access OSS from other Alibaba Cloud services in the same region, use an internal endpoint. For details about supported regions and endpoints, see Regions and endpoints.

  • In this topic, access credentials are obtained from environment variables. For more information about how to configure access credentials, see Configure access credentials.

  • In this topic, an OSSClient instance is created by using an OSS endpoint. If you want to create an OSSClient instance by using custom domain names or Security Token Service (STS), see Configuration examples for common scenarios.

Sample code

Configure upload callbacks for simple upload tasks

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.Callback;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;

import java.io.ByteArrayInputStream;

public class Demo {

    public static void main(String[] args) throws Exception{
        // Specify the endpoint of the region. In this example, the endpoint of the China (Hangzhou) region is used. 
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Specify the name of the bucket. Example: examplebucket. 
        String bucketName = "examplebucket";
        // Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path. 
        String objectName = "exampledir/exampleobject.txt";
        // Specify the address of the server to which the callback request is sent. Example: https://example.com:23450. 
        String callbackUrl = "yourCallbackServerUrl";
        // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. 
        String region = "cn-hangzhou";

        // Create an OSSClient instance and set the signature version to V4. 
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);        
        OSS ossClient = OSSClientBuilder.create()
        .endpoint(endpoint)
        .credentialsProvider(credentialsProvider)
        .clientConfiguration(clientBuilderConfiguration)
        .region(region)               
        .build();
        
        try {
            String content = "Hello OSS";
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName,new ByteArrayInputStream(content.getBytes()));

            // Configure upload callback parameters.
            Callback callback = new Callback();
            callback.setCallbackUrl(callbackUrl);
            // (Optional) Specify the CallbackHost field in the callback request header. 
            // callback.setCallbackHost("yourCallbackHost");
            
            // Set the callback request body in JSON format and define placeholder variables within. 
            callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
            callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");

            // Configure custom parameters for the callback request. Each custom parameter consists of a key and a value. The key must start with x:. 
            callback.addCallbackVar("x:var1", "value1");
            callback.addCallbackVar("x:var2", "value2");
            putObjectRequest.setCallback(callback);

            // Perform the upload operation.
            PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);

            // Read the message content returned from the upload callback. 
            byte[] buffer = new byte[1024];
            putObjectResult.getResponse().getContent().read(buffer);
            // You must close the obtained stream after the data is read. Otherwise, connection leaks may occur. Consequently, no connections are available and an exception occurs. 
            putObjectResult.getResponse().getContent().close();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (Throwable ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

Configure upload callbacks for multipart upload tasks

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class Demo {

    public static void main(String[] args) throws Exception {
        // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Specify the name of the bucket. Example: examplebucket. 
        String bucketName = "examplebucket";
        // Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path. 
        String objectName = "exampledir/exampleobject.txt";
        // Specify the full path of the local file that you want to upload. 
        String filePath = "D:\\localpath\\examplefile.txt";
        // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. 
        String region = "cn-hangzhou";
        // Specify the address of the server to which the callback request is sent. Example: https://example.com:23450. 
        String callbackUrl = "https://example.com:23450";

        // Create an OSSClient instance and set the signature version to V4. 
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        try {
            // Create an InitiateMultipartUploadRequest object. 
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);

            // Configure object metadata and retrieve the Content-Type of the object. 
            ObjectMetadata metadata = new ObjectMetadata();
            if (metadata.getContentType() == null) {
                metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
            }
            System.out.println("Content-Type: " + metadata.getContentType());

            // Include the metadata in the upload request. 
            request.setObjectMetadata(metadata);

            // Initialize the multipart upload task. 
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
            // Obtain the upload ID. 
            String uploadId = upresult.getUploadId();

            // partETags is the set of PartETags. The PartETag of a part consists of the part number and ETag value of the part. 
            List<PartETag> partETags = new ArrayList<PartETag>();
            // Specify the size of each part, which is used to calculate the number of parts of the object. Unit: bytes. 
            Each part can be 100 KB to 5 GB in size. The size of the last part can be less than 100 KB. 
            // Set the part size in bytes. In this example, the part size is set to 1 MB. 
            final long partSize = 1 * 1024 * 1024L;

            // Calculate the number of parts based on the size of the uploaded data. In the following sample code, a local file is used as an example to describe how to use the File.length() method to obtain the size of the uploaded data. 
            final File sampleFile = new File(filePath);
            long fileLength = sampleFile.length();
            int partCount = (int) (fileLength / partSize);
            if (fileLength % partSize != 0) {
                partCount++;
            }
            // Upload all parts of the object. 
            for (int i = 0; i < partCount; i++) {
                long startPos = i * partSize;
                long curPartSize = (i + 1 == partCount) ?  (fileLength - startPos) : partSize;
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(bucketName);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);

                // Specify the input stream of the multipart upload task. 
                // In the following sample code, a local file is used as an example to describe how to create a FileInputStream object and use the InputStream.skip() method to skip the specified data. 
                InputStream instream = new FileInputStream(sampleFile);
                instream.skip(startPos);
                uploadPartRequest.setInputStream(instream);
                // Specify the size available for each part. 
                uploadPartRequest.setPartSize(curPartSize);
                // Specify part numbers. Each part has a part number that ranges from 1 to 10,000. If the part number that you specify does not fall within the specified range, the InvalidArgument error code is returned. 
                uploadPartRequest.setPartNumber(i + 1);
                // Parts are not necessarily uploaded in sequence and can be uploaded from different OSS clients. OSS sorts the parts based on the part numbers and combines the parts into a complete object. 
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                // After a part is uploaded, OSS returns a result that contains a PartETag. The PartETag is stored in partETags. 
                partETags.add(uploadPartResult.getPartETag());

                // Disable the input stream.
                instream.close();
            }

            // Create a CompleteMultipartUploadRequest object. 
            // When you call the CompleteMultipartUpload operation, you must provide all valid PartETags. After OSS receives the PartETags, OSS verifies all parts one by one. After all parts are verified, OSS combines these parts into a complete object. 
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);

            // Specify the upload callback parameters. 
            Callback callback = new Callback();
            callback.setCallbackUrl(callbackUrl);
            // (Optional) Specify the CallbackHost field in the callback request header. 
            // callback.setCallbackHost("yourCallbackHost");

            // Set the callback request body in JSON format and define placeholder variables within. 
            callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
            callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");

            // Configure custom parameters for the callback request. Each custom parameter consists of a key and a value. The key must start with x:. 
            callback.addCallbackVar("x:var1", "value1");
            callback.addCallbackVar("x:var2", "value2");
            completeMultipartUploadRequest.setCallback(callback);

            // Complete the multipart upload task. 
            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
            System.out.println("Upload successful,ETag:" + completeMultipartUploadResult.getETag());

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught a ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

Upload an object by using a form and configure upload callback settings

import com.aliyun.oss.ClientException;
import com.aliyun.oss.common.auth.ServiceSignature;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.StringUtils;
import com.aliyun.oss.internal.OSSUtils;
import com.aliyun.oss.model.Callback;
import org.apache.commons.codec.binary.Base64;
import javax.activation.MimetypesFileTypeMap;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class PostObjectCallbackV4Demo {
    // Specify the full path of the local file that you want to upload. 
    private static final String localFilePath = "D:\\localpath\\examplefile.txt";
    // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
    private static final String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
    // The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations in OSS poses a significant security risk. We recommend that you call API operations or perform routine O&M as a Resource Access Management (RAM) user. To create a RAM user, log on to the RAM console. 
    private static final String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");
    private static final String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");
    // Specify the name of the bucket. Example: examplebucket. 
    private static final String bucketName = "examplebucket";
    // Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path. 
    private static final String objectName = "exampledir/exampleobject.txt";
    // Specify the URL of the server to which you want to send the callback request. Example: http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450 or http://127.0.0.1:9090. 
    private static final String callbackServerUrl = "http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450";
    // Specify the Host header in the callback request. Example: oss-cn-hangzhou.aliyuncs.com. 
    private static final String callbackServerHost = "";
    // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. 
    private static final String region = "cn-hangzhou";
    private static Date requestDateTime = new Date();


    /**
     * Perform form upload. 
     * @throws Exception
     */
    private void PostObject() throws Exception {

        // Add the bucket name to the URL. The URL format is http://yourBucketName.oss-cn-hangzhou.aliyuncs.com. 
        String urlStr = endpoint.replace("https://", "https://" + bucketName+ ".");
        // Construct the form parameters.
        Map<String, String> formFields = new LinkedHashMap<String, String>();
        formFields.put("key", objectName);
        formFields.put("Content-Disposition", "attachment;filename="
                + localFilePath);
        // Specify callback parameters. 
        Callback callback = new Callback();
        // Specify the URL of the server to which you want to send the callback request. Example: http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450 or http://127.0.0.1:9090. 
        callback.setCallbackUrl(callbackServerUrl);
        // Specify the Host header in the callback request. Example: oss-cn-hangzhou.aliyuncs.com. 
        callback.setCallbackHost(callbackServerHost);

        // Set the callback request body in JSON format and define placeholder variables within. 
        callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
        callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");

        // Specify the custom parameters in the callback request. Each custom parameter consists of a key-value pair. The key must start with x: and be in lower case. 
        callback.addCallbackVar("x:var1", "value1");
        callback.addCallbackVar("x:var2", "value2");
        // Specify the callback parameter in Map for the form. 
        setCallBack(formFields, callback);

        // Specify OSSAccessKeyId. 
        formFields.put("OSSAccessKeyId", accessKeyId);
        String policy = "{\"expiration\": \"2120-01-01T12:00:00.000Z\",\"conditions\": [" +
                "  {\"x-oss-signature-version\": \"OSS4-HMAC-SHA256\"},\n" +
                "  {\"x-oss-credential\": \""+accessKeyId+"/"+getDate()+"/"+region+"/oss/aliyun_v4_request\"},\n" +
                "  {\"x-oss-date\": \""+getDateTime()+"\"},\n" +
                "  [\"content-length-range\", 0, 104857600]" +
                "]}";
        String encodePolicy = new String(Base64.encodeBase64(policy.getBytes()));
        // Set the policy. 
        formFields.put("policy", encodePolicy);
        System.out.println("policy:" + policy);
        // Generate a signature. 
        formFields.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
        formFields.put("x-oss-credential", accessKeyId+"/"+getDate()+"/"+region+"/oss/aliyun_v4_request");
        formFields.put("x-oss-date", getDateTime());

        String stringToSign = new String(Base64.encodeBase64(policy.getBytes()));
        System.out.println("stringToSign:" + stringToSign);
        byte[] signingKey = buildSigningKey();
        String signature = buildSignature(signingKey, stringToSign);
        formFields.put("x-oss-signature", signature);
        System.out.println("Signature:" + signature);

        // Perform the upload operation.
        String ret = formUpload(urlStr, formFields);
        System.out.println("Post Object [" + objectName + "] to bucket [" + bucketName + "]");
        System.out.println("post reponse:" + ret);
    }

    private static String formUpload(String urlStr, Map<String, String> formFields)
            throws Exception {
        String res = "";
        HttpURLConnection conn = null;
        String boundary = "9431149156168";
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + boundary);

            // Process form fields.
            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // Recursively read all Map data for the form and write the data to the output stream. 
            if (formFields != null) {
                StringBuilder strBuf = new StringBuilder();
                Iterator<Map.Entry<String, String>> iter = formFields.entrySet().iterator();
                int i = 0;
                while (iter.hasNext()) {
                    Map.Entry<String, String> entry = iter.next();
                    String inputName = entry.getKey();
                    String inputValue = entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    if (i == 0) {
                        strBuf.append("--").append(boundary).append("\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\"").append(inputName).append("\"\r\n\r\n");
                        strBuf.append(inputValue);
                    } else {
                        strBuf.append("\r\n").append("--").append(boundary).append("\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\""
                                + inputName + "\"\r\n\r\n");
                        strBuf.append(inputValue);
                    }
                    i++;
                }
                out.write(strBuf.toString().getBytes());
            }
            // Read the file and write it to the output stream. 
            File file = new File(localFilePath);
            String filename = file.getName();
            String contentType = new MimetypesFileTypeMap().getContentType(file);
            if (contentType == null || contentType.equals("")) {
                contentType = "application/octet-stream";
            }
            StringBuffer strBuf = new StringBuffer();
            strBuf.append("\r\n").append("--").append(boundary)
                    .append("\r\n");
            strBuf.append("Content-Disposition: form-data; name=\"file\"; "
                    + "filename=\"" + filename + "\"\r\n");
            strBuf.append("Content-Type: " + contentType + "\r\n\r\n");
            out.write(strBuf.toString().getBytes());
            DataInputStream in = new DataInputStream(new FileInputStream(file));
            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = in.read(bufferOut)) != -1) {
                out.write(bufferOut, 0, bytes);
            }
            in.close();
            byte[] endData = ("\r\n--" + boundary + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();
            // Read the returned data. 
            strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (ClientException e) {
            System.err.println("Send post request exception: " + e);
            System.err.println(e.getErrorCode()+" msg="+e.getMessage());
            throw e;
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }
    private static void setCallBack(Map<String, String> formFields, Callback callback) {
        if (callback != null) {
            String jsonCb = OSSUtils.jsonizeCallback(callback);
            String base64Cb = BinaryUtil.toBase64String(jsonCb.getBytes());
            formFields.put("callback", base64Cb);
            if (callback.hasCallbackVar()) {
                Map<String, String> varMap = callback.getCallbackVar();
                for (Map.Entry<String, String> entry : varMap.entrySet()) {
                    formFields.put(entry.getKey(), entry.getValue());
                }
            }
        }
    }

    private static String getDateTime() {
        return getIso8601DateTimeFormat().format(requestDateTime);
    }

    private static DateFormat getIso8601DateTimeFormat() {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US);
        df.setTimeZone(new SimpleTimeZone(0, "GMT"));
        return df;
    }

    private static DateFormat getIso8601DateFormat() {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd", Locale.US);
        df.setTimeZone(new SimpleTimeZone(0, "GMT"));
        return df;
    }

    private static String getDate() {
        return getIso8601DateFormat().format(requestDateTime);
    }

    private String buildSignature(byte[] signingKey, String stringToSign) {
        byte[] result = ServiceSignature.create("HmacSHA256").computeHash(signingKey, stringToSign.getBytes(StringUtils.UTF8));
        return BinaryUtil.toHex(result);
    }

    private byte[] buildSigningKey() {
        ServiceSignature signature = ServiceSignature.create("HmacSHA256");
        byte[] signingSecret = ("aliyun_v4" + accessKeySecret).getBytes(StringUtils.UTF8);
        byte[] signingDate = signature.computeHash(signingSecret, getDate().getBytes(StringUtils.UTF8));
        byte[] signingRegion = signature.computeHash(signingDate, region.getBytes(StringUtils.UTF8));
        byte[] signingService = signature.computeHash(signingRegion, "oss".getBytes(StringUtils.UTF8));
        /*System.out.println("signingSecret:\n" + BinaryUtil.toHex(signingSecret));
        System.out.println("signingDate:\n" + BinaryUtil.toHex(signingDate));
        System.out.println("signingRegion:\n" + BinaryUtil.toHex(signingRegion));
        System.out.println("signingService:\n" + BinaryUtil.toHex(signingService));*/
        return signature.computeHash(signingService, "aliyun_v4_request".getBytes(StringUtils.UTF8));
    }

    public static void main(String[] args) throws Exception {
        PostObjectCallbackV4Demo ossPostObject = new PostObjectCallbackV4Demo();
        ossPostObject.PostObject();
    }
}

Configure upload callbacks for resumable upload tasks

package Callback;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;

import java.io.File;

public class Demo {
    public static void main(String[] args) throws Exception {
        // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Specify the name of the bucket. Example: examplebucket. 
        String bucketName = "examplebucket";
        // Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path. 
        String objectName = "exampledir/exampleobject.txt";
        // Specify the full path of the local file. Example: D:\\localpath\\examplefile.txt. 
        String filePath = "D:\\localpath\\examplefile.txt";
        // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. 
        String region = "cn-hangzhou";
        // Specify the address of the server to which the callback request is sent. Example: https://example.com:23450. 
        String callbackUrl = "http://example.com:23450/callback";

        // Create an OSSClient instance. 
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        try {
            // Configure object metadata and retrieve the Content-Type of the object. 
            ObjectMetadata metadata = new ObjectMetadata();
            if (metadata.getContentType() == null) {
                metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
            }
            System.out.println("Content-Type: " + metadata.getContentType());

            // Configure multiple parameters by using UploadFileRequest. 
            // Specify the name of the bucket such as examplebucket and the full path of the object such as exampledir/exampleobject.txt. Do not include the bucket name in the full path. 
            UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName,objectName);

            // Configure a single parameter by using UploadFileRequest. 
            // Specify the full path of the local file. Example: D:\\localpath\\examplefile.txt. By default, if you do not specify the path of the local file, the file is uploaded from the local path of the project to which the sample program belongs. 
            uploadFileRequest.setUploadFile(filePath);
            // Specify the number of concurrent threads for the upload task. Default value: 1. 
            uploadFileRequest.setTaskNum(5);
            // Specify the part size. Unit: bytes. Valid values: 100 KB to 5 GB. Default value: 100 KB. 
            uploadFileRequest.setPartSize(1 * 1024 * 1024);
            // Specify whether to enable resumable upload. By default, resumable upload is disabled. 
            uploadFileRequest.setEnableCheckpoint(true);
            // Specify the checkpoint file that records the upload progress of each part. This file stores information about upload progress. If a part fails to be uploaded, the task can be continued based on the progress recorded in the checkpoint file. After the object is uploaded, the checkpoint file is deleted. 
            // By default, if you do not specify this parameter, this checkpoint file shares the same directory as the object you want to upload. The directory is named ${uploadFile}.ucp. 
            uploadFileRequest.setCheckpointFile("yourCheckpointFile");
            // Configure object metadata. 
            uploadFileRequest.setObjectMetadata(metadata);

            // Configure upload callback parameters.
            Callback callback = new Callback();
            callback.setCallbackUrl(callbackUrl);
            // (Optional) Specify the CallbackHost field in the callback request header. 
            // callback.setCallbackHost("yourCallbackHost");

            // Set the callback request body in JSON format and define placeholder variables within. 
            callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
            callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");

            // Configure custom parameters for the callback request. Each custom parameter consists of a key and a value. The key must start with x:. 
            callback.addCallbackVar("x:var1", "value1");
            callback.addCallbackVar("x:var2", "value2");
            // Configure an upload callback. The parameter type is Callback. 
            uploadFileRequest.setCallback(callback);

            // Start resumable upload. 
            ossClient.uploadFile(uploadFileRequest);

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (Throwable ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            // Shut down the OSSClient instance. 
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

Use a presigned URL to upload an object and set upload callback parameters

  1. Generate a presigned URL that includes upload callback parameters to enable uploads using HTTP PUT requests.

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    
    import java.net.URL;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    public class OssPresignExample {
        public static void main(String[] args) throws Throwable {
            // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // Specify the name of the bucket. Example: examplebucket. 
            String bucketName = "examplebucket";
            // Specify the full path of the object. Example: exampleobject.txt. Do not include the bucket name in the full path. 
            String objectName = "exampleobject.txt";
            // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. 
            String region = "cn-hangzhou";
    
            // Create an OSSClient instance. 
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            URL signedUrl = null;
            try {
                // Construct callback parameters.
                String callbackUrl = "http://www.example.com/callback";
                String callbackBody = "{\"callbackUrl\":\"" + callbackUrl + "\",\"callbackBody\":\"bucket=${bucket}&object=${object}&my_var_1=${x:var1}&my_var_2=${x:var2}\"}";
                String callbackBase64 = Base64.getEncoder().encodeToString(callbackBody.getBytes());
    
                String callbackVarJson = "{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}";
                String callbackVarBase64 = Base64.getEncoder().encodeToString(callbackVarJson.getBytes());
                // Specify request headers. 
                Map<String, String> headers = new HashMap<String, String>();
                // Specify the callback parameter. 
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK, callbackBase64);
                // Specify the callback-var parameter. 
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK_VAR, callbackVarBase64);
    
                // Set the validity period to 3600 seconds.
                Date expiration = new Date(new Date().getTime() + 3600 * 1000);
    
                // Format the expiration time.
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                String expirationStr = dateFormat.format(expiration);
    
                // Construct a request.
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName);
                request.setMethod(HttpMethod.PUT);
                request.setExpiration(expiration);
                // Add headers to the request. 
                request.setHeaders(headers);
    
                // Output the values of the callback and callback-var parameters.
                System.out.println("callback:"+callbackBase64);
                System.out.println("callback-var:"+callbackVarBase64);
    
                // Generate a presigned URL.
                URL url = ossClient.generatePresignedUrl(request);
    
                // Output the result.
                System.out.println("method: PUT,");
                System.out.println(" expiration: " + expirationStr + ",");
                System.out.println(" url: " + url);
    
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            }
        }
    }
  2. Use the presigned URL to upload an object.

    curl

    curl -X PUT \
         -H "x-oss-callback: eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9" \
         -H "x-oss-callback-var: eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==" \
         -T "C:\\Users\\demo.txt" \
         "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"

    Python

    import requests
    
    def upload_file(signed_url, file_path, headers=None):
        """
        Use a presigned URL to upload an object to OSS.
    
        :param signed_url: Presigned URL.
        :param file_path: Full path of the local file to be uploaded.
        :param headers: Request headers. This parameter is optional.
        :return: None
        """
        if not headers:
            headers = {}
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"Status code:{response.status_code}")
                if response.status_code == 200:
                    print("The object is uploaded by using the library.")
                else:
                    print("Upload failed.")
                print(response.text)
        except Exception as e:
            print(f"An error occurred:{e}")
    
    if __name__ == "__main__":
        # Replace <signedUrl> with the presigned URL.
        signed_url = "<signedUrl>"
    
        # Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the directory in which the script is stored.
        file_path = "C:\\Users\\demo.txt"
    
        headers = {
            "x-oss-callback": "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
            "x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
        }
    
        upload_file(signed_url,  file_path, headers)

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io"
    
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string) error {
    	// Open the file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// Read the content.
    	fileBytes, err := io.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// Create a request.
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// Specify request headers.
    	for key, value := range headers {
    		req.Header.Add(key, value)
    	}
    
    	// Send the request.
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// Process the response.
    	fmt.Printf("Status code:%d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("The object is uploaded by using the library.")
    	} else {
    		fmt.Println("Upload failed.")
    	}
    	body, _ := io.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Replace <signedUrl> with the presigned URL.
    	signedUrl := "<signedUrl>"
    	// Specify the full path of the local file. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs.
    	filePath := "C:\\Users\\demo.txt"
    
    	// Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated.
    	headers := map[string]string{
    		"x-oss-callback":     "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
    		"x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers)
    	if err != nil {
    		fmt.Printf("An error occurred:%v\n", err)
    	}
    }
    

    Java

    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.entity.FileEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import java.io.*;
    import java.net.URL;
    import java.util.*;
    
    public class SignUrlUpload {
        public static void main(String[] args) throws Throwable {
            CloseableHttpClient httpClient = null;
            CloseableHttpResponse response = null;
    
            // Replace <signedUrl> with the presigned URL.
            URL signedUrl = new URL("<signedUrl>");
    
            // Specify the full path of the local file. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs.
            String pathName = "C:\\Users\\demo.txt";
    
            // Specify request headers, including x-oss-callback and x-oss-callback-var.
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("x-oss-callback", "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9");
            headers.put("x-oss-callback-var", "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==");
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                // If you configure headers when the presigned URL was generated, these headers must be sent to the server when the presigned URL is used to upload a file. If the headers that are sent to the server for the signature calculation are different from the headers specified when the presigned URL was generated, a signature error is reported.
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Status code:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("The object is uploaded by using the library.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    PHP

    <?php
    
    function uploadFile($signedUrl, $filePath, $headers = []) {
        // Check whether the file exists.
        if (!file_exists($filePath)) {
            echo "The file does not exist: $filePath\n";
            return;
        }
    
        // Initialize a cURL session.
        $ch = curl_init();
    
        // Set cURL options.
        curl_setopt($ch, CURLOPT_URL, $signedUrl);
        curl_setopt($ch, CURLOPT_PUT, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_INFILE, fopen($filePath, 'rb'));
        curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function($key, $value) {
            return "$key: $value";
        }, array_keys($headers), $headers));
    
        // Perform the cURL request.
        $response = curl_exec($ch);
    
        // Query the HTTP status code.
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
        // Close the cURL session.
        curl_close($ch);
    
        // Output the result
        echo "Status code:$httpCode\n";
        if ($httpCode == 200) {
            echo "The object is uploaded by using the library.\n";
        } else {
            echo "Upload failed.\n";
        }
        echo $response . "\n";
    }
    
    // Replace <signedUrl> with the presigned URL.
    $signedUrl = "<signedUrl>";
    
    // Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the directory in which the script is stored.
    $filePath = "C:\\Users\\demo.txt";
    
    $headers = [
        "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
        "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    ];
    
    uploadFile($signedUrl, $filePath, $headers);
    
    ?>

References

  • For the complete sample code for upload callbacks, visit GitHub.

  • For more information about the API operation that you can call to configure upload callbacks, see Callback.