All Products
Search
Document Center

Object Storage Service:How do I force a download of an object from an OSS bucket when the object is accessed by using a custom domain of the bucket?

Last Updated:Apr 28, 2024

If you use a custom domain of an Object Storage Service (OSS) bucket to access an object in the bucket from a browser that supports previews of the object format, OSS specifies that the object is displayed inline in the browser for a preview by default. If you want the object to be downloaded as an attachment when the object is accessed from a browser by using the custom domain, you can use a signed URL in which the response-content-disposition field is set to attachment or set the Content-Disposition metadata header of the object to attachment. The former method forces a download of the object only when the object is accessed by using the URL. The latter method forces a download of the object for any browser-based access to the object.

Use a signed URL to specify forced object downloads

Use OSS SDKs

The following sample code provides an example on how to use OSS SDK for Java to force an object download by using a signed URL:

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import java.net.URL;
import java.util.*;
import java.util.Date;

public class Demo {
    public static void main(String[] args) throws Throwable {
        // Specify a custom domain. 
        String endpoint = "https://example.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();
        // Create a ClientBuilderConfiguration instance. You can change the default values of parameters based on your business requirements. 
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();

        // Specify true in setSupportCname to map the custom domain to the intended bucket. 
        conf.setSupportCname(true);
        // 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";        

        // Create an OSSClient instance. 
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider, conf);

        try {
            // Create a request. 
            GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectName);
            // Set HttpMethod to GET. 
            generatePresignedUrlRequest.setMethod(HttpMethod.GET);
            // Specify the validity period of the signed URL. Unit: milliseconds. In this example, the validity period is set to 1 hour. 
            Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
            generatePresignedUrlRequest.setExpiration(expiration);
            // Specify that the downloaded file uses the original object name. 
            Map<String, String> queryParam = new HashMap<String, String>();
            queryParam.put("response-content-disposition",  "attachment");
            generatePresignedUrlRequest.setQueryParameter(queryParam);
            // Generate the signed URL. 
            URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);
            System.out.println(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());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

Configure the Content-Disposition metadata header to force object downloads

Use the OSS console

  1. Log on to the OSS console.

  2. In the left-side navigation pane, click Buckets. On the Buckets page, find and click the desired bucket.

  3. In the left-side navigation tree, choose Object Management > Objects.

  4. Locate the object in the object list and choose 更多 > Set Object Metadata.

  5. In the Set Object Metadata panel, set Content-Disposition to attachment, retain the default settings for other parameters, and click OK.

  6. Access the object by using the object URL with the custom domain included.

    • For example, the example.jpg object with an access control list (ACL) of public-read or public-read-write is stored in the root directory of the bucket, to which the custom domain example.com is mapped. You can access the object from a browser by using the concatenated http://example.com/example.jpg URL.

    • For example, the example.jpg object with an ACL of private is stored in the root directory of the bucket, to which the custom domain example.com is mapped. You can access the object from a browser by using the signed object URL (http://example.com/example.jpg?SignatureInfo). For more information about how to access a private object by using a custom domain, see Use the custom domain name to access the bucket.

Use OSS SDKs

The following sample code provides an example on how to use OSS SDK for Java to configure object metadata for forced object downloads:

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.ObjectMetadata;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Date;

public class Test {
    public static void main(String[] args) throws Exception {

        // Specify a custom domain. 
        String endpoint = "https://example.com";
        // For security purposes, we recommend that you do not save access credentials in the project code. In this example, access credentials are obtained from environment variables. Before you run the sample code, make sure that the environment variables are configured. 
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Create a ClientBuilderConfiguration instance. You can change the default values of parameters based on your business requirements. 
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();

        // Specify true in setSupportCname to map the custom domain to the intended bucket. 
        conf.setSupportCname(true);
        // Specify the name of the bucket. Example: examplebucket. 
        String bucketName = "examplebucket";
        // Specify the full path of the object. Do not include the bucket name in the full path. Example: testfolder/exampleobject.txt. 
        String objectName = "testfolder/exampleobject.txt";
        // Specify the content of the object. 
        String content = "Hello OSS";

        // Create an OSSClient instance. 
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider, conf);

        try {
            // Create object metadata. You can specify standard HTTP headers in object metadata. 
            ObjectMetadata meta = new ObjectMetadata();

            String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5(content.getBytes()));
            // Enable MD5 verification. After MD5 verification is enabled, OSS calculates the MD5 hash of the uploaded object and compares this MD5 hash with that specified in the request. If the two values are different, an error is reported. 
            meta.setContentMD5(md5);
            // Specify the type of content to upload. The browser determines the format and encoding type that are used to read the object based on the content type of the object. If the content type is not specified, OSS assigns a content type based on the object name extension. If no extension is available, the default value application/octet-stream is used as the content type. 
            meta.setContentType("text/plain");
            // Specify that the downloaded file uses the original object name. If the name contains Chinese characters, URL-encode the name. 
            meta.setContentDisposition("attachment"+ URLEncoder.encode("UTF-8")+";"+URLEncoder.encode("UTF-8"));
            // Specify the length of the object that can be uploaded. If the actual object length is greater than the specified length, only the specified length of the content is uploaded and the trailing part is truncated. If the actual object length is smaller than the specified length, all content of the object is uploaded. 
            // meta.setContentLength(content.length());
            // Specify the caching behavior of the web page when the content is downloaded. 
            // meta.setCacheControl("Download Action");
            // Specify the expiration time of the cache in UTC. 
            // meta.setExpirationTime(DateUtil.parseIso8601Date("2025-10-12T00:00:00.000Z"));

            // Configure user metadata. 
            // meta.setHeader("yourHeader", "yourHeaderValue");

            // Upload the object. 
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()), meta);

            // Verify whether the object is downloaded when it is accessed by using the URL of the object. 
            Date expiration = new Date(new Date().getTime() + 3600 * 1000);
            GeneratePresignedUrlRequest signRequest = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
            signRequest.setExpiration(expiration);
            URL signedUrl = ossClient.generatePresignedUrl(signRequest);
            System.out.println(signedUrl);

        } 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());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

References