By default, when a browser that supports inline preview opens an OSS object through a custom domain, OSS renders the object inline rather than downloading it. To force the browser to download the object as an attachment instead, set the Content-Disposition response header to attachment. OSS supports two methods, each with a different scope of effect.
Choose a method
| Method | Scope | When to use |
|---|---|---|
Add response-content-disposition=attachment to a signed URL | Per-request only. Only the specific signed URL triggers a download. | Temporary or one-off download links |
Set Content-Disposition: attachment in object metadata | Permanent. Every browser access to the object triggers a download. | Objects that should always be downloaded, regardless of how they are accessed |
Use a signed URL to force a download
When a browser accesses a signed URL with response-content-disposition=attachment, the browser downloads the object as an attachment. Other accesses to the same object are not affected.
Use OSS SDK for Java
Prerequisites
Before you begin, make sure that:
The custom domain is mapped to the bucket (CNAME record configured)
The
OSS_ACCESS_KEY_IDandOSS_ACCESS_KEY_SECRETenvironment variables are set with valid credentials
The following example uses GeneratePresignedUrlRequest to generate a signed URL that includes response-content-disposition=attachment.
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 {
// Custom domain mapped to the bucket
String endpoint = "https://example.com";
// Load credentials from environment variables
EnvironmentVariableCredentialsProvider credentialsProvider =
CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
// Required: map the custom domain (CNAME) to the bucket
conf.setSupportCname(true);
String bucketName = "examplebucket";
String objectName = "exampleobject.txt";
// Call shutdown() to release resources when the client is no longer in use
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider, conf);
try {
GeneratePresignedUrlRequest request =
new GeneratePresignedUrlRequest(bucketName, objectName);
request.setMethod(HttpMethod.GET);
// Set URL expiration to 1 hour
request.setExpiration(new Date(new Date().getTime() + 3600 * 1000L));
// Add response-content-disposition=attachment to force download
Map<String, String> queryParam = new HashMap<>();
queryParam.put("response-content-disposition", "attachment");
request.setQueryParameter(queryParam);
URL url = ossClient.generatePresignedUrl(request);
System.out.println(url);
} catch (OSSException oe) {
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("Error Message: " + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}When a user opens the generated URL in a browser, the browser presents a Save As dialog instead of rendering the object inline.
Set Content-Disposition in object metadata to force downloads permanently
Setting Content-Disposition: attachment in an object's metadata makes every browser access to that object trigger a download, regardless of the URL used. Configure this either through the OSS console or programmatically using the SDK.
Use the OSS console
Log on to the OSS console.
In the left-side navigation pane, click Buckets. On the Buckets page, find and click the desired bucket.
In the left-side navigation tree, choose Object Management > Objects.
Locate the object, then choose  > Set Object Metadata.
In the Set Object Metadata panel, set Content-Disposition to
attachment, leave other settings unchanged, and click OK.Access the object using the custom domain URL:
Public-read or public-read-write ACL: Open
http://example.com/example.jpgdirectly in a browser.Private ACL: Generate a signed URL (for example,
http://example.com/example.jpg?SignatureInfo) and open it in a browser. For details, see Use the custom domain name to access the bucket.
Use OSS SDK for Java
The following example uploads an object with Content-Disposition: attachment set in its metadata. After the upload, the object always triggers a download when accessed from a browser.
Prerequisites
Before you run the sample code, make sure that:
The
OSS_ACCESS_KEY_IDandOSS_ACCESS_KEY_SECRETenvironment variables are set with valid credentialsThe custom domain is mapped to the bucket (CNAME record configured)
Sample code
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 {
// Custom domain mapped to the bucket
String endpoint = "https://example.com";
// Load credentials from environment variables
EnvironmentVariableCredentialsProvider credentialsProvider =
CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
// Required: map the custom domain (CNAME) to the bucket
conf.setSupportCname(true);
String bucketName = "examplebucket";
String objectName = "testfolder/exampleobject.txt";
String content = "Hello OSS";
// Call shutdown() to release resources when the client is no longer in use
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider, conf);
try {
ObjectMetadata meta = new ObjectMetadata();
// Enable MD5 verification: OSS compares the computed MD5 with this value
// and returns an error if they differ
String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5(content.getBytes()));
meta.setContentMD5(md5);
// Set content type. If omitted, OSS infers it from the file extension.
// If no extension is present, defaults to application/octet-stream.
meta.setContentType("text/plain");
// Force download: set Content-Disposition to attachment.
// URL-encode filenames that contain non-ASCII characters.
meta.setContentDisposition("attachment" + URLEncoder.encode("UTF-8") + ";" + URLEncoder.encode("UTF-8"));
// Upload the object with metadata
ossClient.putObject(
bucketName,
objectName,
new ByteArrayInputStream(content.getBytes()),
meta
);
// Verify: generate a signed URL and open it in a browser to confirm download behavior
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("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("Error Message: " + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}Open the signed URL printed to the console in a browser. The browser should present a Save As dialog, confirming that the metadata is applied correctly.
What's next
To use a custom filename in the Save As dialog instead of the original object name, see Specify names for downloaded objects.
To configure the reverse behavior — ensuring an object is previewed inline rather than downloaded — see What do I do if an object cannot be previewed when I access the object?