All Products
Search
Document Center

Object Storage Service:Download objects based on the last modified time or ETags of objects

Last Updated:Jan 23, 2024

When you download an object from an Object Storage Service (OSS) bucket, you can specify download conditions based on the last modified time or the ETag of the object. If the specified download conditions are met, the object is downloaded. Otherwise, an error is returned and the object is not downloaded. This way, you can avoid repeatedly downloading the same object to reduce network traffic and resource usage and improve download efficiency.

Prerequisites

  • Objects are uploaded to OSS. For more information, see Upload objects.

  • An Archive object is restored or real-time access of Archive objects is enabled for the bucket that stores the Archive object if you want to download the Archive object. For more information, see Restore objects and Real-time access of Archive objects.

  • A Cold Archive or Deep Cold Archive object is restored if you want to download the object. For more information, see Restore objects.

  • The oss:GetObject permission is granted to a Resource Access Management (RAM) user if you want to use the RAM user to perform conditional download. For more information, see Common examples of RAM policies.

Scenarios

  • Application resource update: An application downloads an object only when it detects that the ETag of the object is changed or the last modified time of the object is updated. This minimizes data usage and optimizes user experience.

  • Data synchronization and incremental backup: Only objects whose ETags are changed or whose last modified time is updated are synchronized or backed up. This reduces bandwidth costs and ensures data timeliness and consistency.

  • Object sharing and synchronization: You can use the Etags or the last modified time of objects to verify whether the objects are changed and then synchronize the changed objects. This accelerates work collaboration and reduces data consumption.

Download conditions

The following table describes the available object download conditions.

Header

Description

If-Modified-Since

If the time specified in this header is earlier than the last modified time of the object or is invalid, the object and 200 OK are returned. Otherwise, 304 Not Modified is returned.

The time must be in GMT. Example: Fri, 13 Nov 2015 14:47:53 GMT.

By default, this header is left empty.

If-Unmodified-Since

If the time specified in this header is the same as or later than the last modified time of the object, the object and 200 OK are returned. Otherwise, 412 Precondition Failed is returned.

The time must be in GMT. Example: Fri, 13 Nov 2015 14:47:53 GMT.

You can specify both the If-Modified-Since and If-Unmodified-Since headers in a request.

By default, this header is left empty.

If-Match

If the ETag specified in this header matches the ETag of the object, the object and 200 OK are returned. Otherwise, 412 Precondition Failed is returned.

The ETag of an object is used to check the data integrity of the object.

By default, this header is left empty.

If-None-Match

If the ETag specified in this header does not match the ETag of the object, the object and 200 OK are returned. Otherwise, 304 Not Modified is returned.

You can specify both the If-Match and If-None-Match headers in a request.

By default, this header is left empty.

Important

You cannot perform conditional download by using the OSS console or ossutil.

Procedure

Use OSS SDKs

The following sample code provides examples on how to perform conditional download by using OSS SDK for common programming languages to call GetObject. For more information about how to perform conditional download by using OSS SDKs for other programming languages, see Overview.

Java

import com.aliyun.oss.ClientException;
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.model.GetObjectRequest;
import java.io.File;
import java.util.Date;

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. Do not include the bucket name in the full path. Example: testfolder/exampleobject.txt. 
        String objectName = "testfolder/exampleobject.txt";
        String pathName = "D:\\localpath\\examplefile.txt";

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

        try {
            GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
            // For example, an object was last modified at 13:27:04, September 26, 2023. If the specified time is earlier than the last modified time, such as Tue Sep 25 13:27:04 CST 2023, the object meets the If-Modified-Since condition and the object is downloaded. 
            request.setModifiedSinceConstraint(new Date("Tue Sep 25 13:27:04 CST 2023"));

            // Download the object to your local device. 
            ossClient.getObject(request, new File(pathName));
        } 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();
            }
        }
    }
}
        

PHP

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;

// Obtain access credentials from environment variables. Before you run the sample code, make sure that you specified the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables.  
$accessKeyId = getenv("OSS_ACCESS_KEY_ID"); 
$accessKeySecret = getenv("OSS_ACCESS_KEY_SECRET");
// In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// Specify the name of the bucket. 
$bucket= "<yourBucketName>";
// Specify the object name. The object name is the full path of the object. The path of the object cannot contain the bucket name. Example: exampledir/exampleobject.txt. 
$object = "<yourObjectName>";
// Specify the full path of the local file that you want to upload. Example: D:\\localpath\\examplefile.txt. 
$localfile = "<yourLocalFile>";

try{
    $options = array(
        OssClient::OSS_HEADERS => array(          
           // Set If-Modified-Since to 14:47:53 Friday, April 9, 2021 in GMT. 
          OssClient::OSS_IF_MODIFIED_SINCE => "Fri, 9 Apr 2021 14:47:53 GMT",
          // Set If-Unmodified-Since to 14:47:53 Wednesday, October 13, 2021 in GMT. 
          OssClient::OSS_IF_UNMODIFIED_SINCE => "Fri, 13 Oct 2021 14:47:53 GMT",
          // Specify that objects whose ETag values do not match the ETag values that are specified in the requests are downloaded. 
          OssClient::OSS_IF_NONE_MATCH => '"5B3C1A2E0563E1B002CC607C****"',
          // Specify that objects whose ETag values match the ETag values that are specified in the requests are downloaded. 
          OssClient::OSS_IF_MATCH => '"fba9dede5f27731c9771645a3986****"',          
          OssClient::OSS_FILE_DOWNLOAD => $localfile
        )

    );

    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
    $ossClient->getObject($bucket, $object, $options);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

Node.js

const OSS = require('ali-oss');

const client = new OSS({
  // 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 oss-cn-hangzhou. 
  region: 'yourRegion',
  // Obtain access credentials from environment variables. Before you run the sample code, make sure that you have configured environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET. 
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // Specify the name of the bucket. 
  bucket: 'examplebucket'
});

async function main() {
  try {
    // Upload an object named exampleobject.txt. 
    await client.put("exampleobject.txt", Buffer.from("contenttest"));
    // Set the If-Modified-Since header in the request. If the value of this header is earlier than the time when the uploaded object is last modified, the object is downloaded. 
    let result = await client.get("exampleobject.txt", {
      headers: {
        "If-Modified-Since": new Date("1970-01-01").toGMTString(),
      },
    });
    console.log(result.content.toString() === "contenttest");
    console.log(result.res.status === 200);

    // If the value of the If-Modified-Since header is equal to or later than the time when the uploaded object is last modified, OSS returns 304 Not Modified. 
    result = await client.get("exampleobject.txt", {
      headers: {
        "If-Modified-Since": new Date().toGMTString(),
      },
    });
    console.log(result.content.toString() === "");
    console.log(result.res.status === 304);
  } catch (e) {
    console.log(e.code === "Not Modified");
  }
}

main();

Python

import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider

# 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. 
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
# Specify the name of the bucket. Example: examplebucket. 
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')
# Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. For more information about the naming conventions for objects, see Object naming conventions. 
object_name = 'exampledir/exampleobject.txt'

headers = dict()
# If the time that is specified in the request is earlier than the actual modified time of the object, the object is downloaded. Otherwise, the error code "304 Not modified" is returned. 
headers['If-Modified-Since'] = 'Mon, 13 Dec 2021 14:47:53 GMT'
# If the time that is specified in the request is the same as or later than the actual modified time of the object, the object is downloaded. Otherwise, the error code 412 Precondition failed is returned. 
# headers['If-Unmodified-Since'] = 'Mon, 13 Dec 2021 14:47:53 GMT'
# If the ETag value that is specified in the request matches the ETag value of the object, the object is downloaded. Otherwise, the error code "412 Precondition failed" is returned. 
# headers['If-Match'] = 'DC21493F505BA3739562D8CC452C****'
# If the ETag value that is specified in the request does not match the ETag value of the object, the object is downloaded. Otherwise, the error code "304 Not modified" is returned. 
# headers['If-None-Match'] = 'DC21493F505BA3739562D8CC452C****'
object_stream = bucket.get_object(object_name, headers=headers)
print(object_stream.read())

Browser.js

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>Document</title>
</head>

<body>
  <button id='upload'>Upload</button>
  <button id='download'>Download</button>
    <!-- Import the SDK file -->
  <script type="text/javascript" src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.16.0.min.js"></script>
  <script type="text/javascript">
      const client = new OSS({
         // 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 oss-cn-hangzhou. 
         region: 'yourRegion',
         // Specify the temporary AccessKey pair obtained from STS. The AccessKey pair consists of an AccessKey ID and an AccessKey secret. 
         accessKeyId: 'yourAccessKeyId',
         accessKeySecret: 'yourAccessKeySecret',
         // Specify the security token that you obtained from STS. 
        stsToken: 'yourSecurityToken',
        // Specify the name of the bucket. Example: examplebucket. 
        bucket: "examplebucket",
      });

    const download = document.getElementById('download')
    const upload = document.getElementById('upload')

    // Upload the object.   
    upload.addEventListener('click', () => {
      // Specify the content of the object to upload. 
      const file = new Blob(['examplecontent'])
      // Specify the full path of the object. Example: exampledir/exampleobject.txt. 
      const fileName = 'exampledir/exampleobject.txt'
      const result = client.put(fileName, file).then(r => console.log(r))
    })

    // Download the object. 
    download.addEventListener('click', () => {
      // Specify the data range of the object to download. 
      const start = 1, end = 5
      client.get('exampledir/exampleobject.txt', {
        headers: {
          // Set the If-Modified-Since header in the request. If the value of this header is earlier than the time when the uploaded object is last modified, the object is downloaded. // If the value of the If-Modified-Since header is equal to or later than the time when the uploaded object is last modified, OSS returns 304 Not Modified. 
          "If-Modified-Since": new Date("1970-01-01").toGMTString()
          // Set the If-Unmodified-Since header in the request. If the value of this header is equal to or later than the time when the uploaded object is last modified, the object is downloaded. If the value of the If-Unmodified-Since header is earlier than the time when the uploaded object is last modified, OSS returns 412 Precondition Failed. 
          //"If-Unmodified-Since": new Date(1970-01-01).toGMTString()
          // Set the If-Match header to an ETag value. If the specified ETag value matches the ETag of the object, the object is downloaded. If the specified ETag value does not match the ETag of the object, OSS returns 412 Precondition Failed. 
          //"If-Match": '5B3C1A2E0563E1B002CC607C****'
          // Set the If-Match header to an ETag value. If the specified ETag value does not match the ETag of the object, the object is downloaded. If the specified ETag value matches the ETag of the object, OSS returns 304 Not Modified. 
          //"If-None-Match": '5B3C1A2E0563E1B002CC607C****'
        },
      }).then(r => {
        if (r.content.length > 0) {                
          const newBlob = new Blob([r.content], { type: r.res.headers['content-type'] });
          const link = document.createElement('a')
          link.href = window.URL.createObjectURL(newBlob)
          link.download = 'foo.txt'
          link.click()
          window.URL.revokeObjectURL(link.href)
        } else {
          console.log ('Error code', r.res.status)
          console.log ('No eligible objects to download')
        }
      })
    })

  </script>
</body>

</html>

Android

public void testGetObjectWithHeaders() throws Exception {
        // Construct an object download request. 
        // Specify the bucket name such as examplebucket and the full path of the object such as exampledir/exampleobject.txt. The full path cannot contain the bucket name. 
        GetObjectRequest request = new GetObjectRequest("examplebucket", "exampledir/exampleobject.txt");
        request.setRequestHeaders(...);


        OSSAsyncTask task = oss.asyncGetObject(request, getCallback);
        task.waitUntilFinished();

        GetObjectRequest rq = getCallback.request;
        GetObjectResult result = getCallback.result;

    }

Go

package main

import (
    "fmt"
    "os"
    "time"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
    // 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. 
    provider, err := oss.NewEnvironmentVariableCredentialsProvider()
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // Create an OSSClient instance. 
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. Specify your actual endpoint. 
    client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // Specify the name of the bucket. 
    bucket, err := client.Bucket("yourBucketName")
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // For example, an object was last modified at 18:43:02, on November 21, 2023. If the specified time is earlier than the last modified time, the object meets the If-Modified-Since condition and the object is downloaded. 
    date := time.Date(2023, time.November, 21, 10, 40, 02, 0, time.UTC)

    // The object is not downloaded if it does not meet the specified conditions. 
    // Specify the full path of the object. Do not include the bucket name in the full path. 
    err = bucket.GetObjectToFile("yourObjectName", "LocalFile", oss.IfUnmodifiedSince(date))    
    if err == nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // The object is downloaded if it meets the specified conditions. 
    err = bucket.GetObjectToFile("yourObjectName", "LocalFile", oss.IfModifiedSince(date))
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
}

iOS

OSSGetObjectRequest *get = [OSSGetObjectRequest new];
// Specify the bucket name. For more information about the naming conventions for buckets, see Bucket naming conventions. 
get.bucketName = @"examplebucket";
// Specify the full path of the object. The path cannot contain the bucket name. For more information about the naming conventions for objects, see Object naming conventions. 
get.objectKey = @"exampledir/exampleobject.txt";
NSMutableDictionary *headerFields = [NSMutableDictionary dictionary];
// Specify that objects that are modified after 14:47:53 Friday, October 13, 2021 in GMT are downloaded. 
[headerFields setValue:@"Fri, 13 Oct 2021 14:47:53 GMT" forKey:@"If-Modified-Since"];
// Specify that objects that are modified at the current time or earlier are downloaded. 
[headerFields setValue:[[NSDate new] oss_asStringValue] forKey:@"If-Unmodified-Since"];
// Specify that objects whose ETag values do not match the ETag values that are specified in the requests are downloaded. 
[headerFields setValue:@"5B3C1A2E0563E1B002CC607C****" forKey:@"If-None-Match"];
// Specify that objects whose ETag values match the ETag values that are specified in the requests are downloaded. 
[headerFields setValue:@"fba9dede5f27731c9771645a3986****" forKey:@"If-Match"];
get.headerFields = headerFields;

[[[_client getObject:get] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    if (!task.error) {
        NSLog(@"get object success!");
    } else {
        NSLog(@"get object error: %@", task.error);
    }
    return nil;
}] waitUntilFinished];

Use the OSS API

If your business requires a high level of customization, you can directly call RESTful APIs. To directly call an API, you must include the signature calculation in your code. For more information, see GetObject.

References

  • For more information about how to download an object from a versioning-enabled bucket, see Manage objects in a versioning-enabled bucket.

  • For more information about how to download an object from a versioning-suspended bucket, see Manage objects in a versioning-suspended bucket.

  • OSS allows you to configure access control lists (ACLs) for buckets and objects. This way, unauthorized third-party users cannot download data from your bucket. For more information, see Overview.

  • If you want to download an object directly from a bucket, you can perform simple download. For more information, see Simple download.

  • If you want to continue interrupted download tasks from where they are interrupted when you download large objects, you can use resumable download. For more information, see Resumable download.

  • If you want to grant third-party users the permissions to download objects from a bucket whose ACL is private, use Security Token Service (STS) to generate temporary access credentials or use signed URLs. For more information, see Authorize third-party users to download objects.