将Cache-Control和Expires标头添加到Azure存储Blob

时间:2010-12-22 09:10:45

标签: c# azure azure-storage-blobs cache-control

我正在使用Azure存储来提供静态文件blob,但我希望在提供服务时为文件/ blob添加Cache-Control和Expires标头以降低带宽成本。

CloudXplorer和Cerebrata的Cloud Storage Studio这样的应用程序提供了在容器和blob上设置元数据属性的选项,但在尝试添加Cache-Control时会感到不安。

有人知道是否可以为文件设置这些标题?

9 个答案:

答案 0 :(得分:23)

我必须在大约600k blob上运行批处理作业,并发现了两件真正有用的东西:

  1. 从同一数据中心的辅助角色运行操作。只要Azure服务位于同一个关联组中,Azure服务之间的速度就很快。此外,没有数据传输费用。
  2. 并行运行操作。 .net v4中的任务并行库(TPL)使这非常简单。下面是为容器中的每个blob并行设置缓存控制头的代码:

    // get the info for every blob in the container
    var blobInfos = cloudBlobContainer.ListBlobs(
        new BlobRequestOptions() { UseFlatBlobListing = true });
    Parallel.ForEach(blobInfos, (blobInfo) =>
    {
        // get the blob properties
        CloudBlob blob = container.GetBlobReference(blobInfo.Uri.ToString());
        blob.FetchAttributes();
    
        // set cache-control header if necessary
        if (blob.Properties.CacheControl != YOUR_CACHE_CONTROL_HEADER)
        {
            blob.Properties.CacheControl = YOUR_CACHE_CONTROL_HEADER;
            blob.SetProperties();
        }
    });
    

答案 1 :(得分:9)

以下是Joel Fillmore答案的更新版本:

Azure不再创建网站和使用WorkerRole,而是能够运行“WebJobs”。您可以在存储帐户所在的同一数据中心的网站上按需运行任何可执行文件,以设置缓存标头或任何其他标头字段。

  1. 在您的存储帐户中创建与同一数据中心相同的临时网站。不要担心亲和团体;创建一个空的ASP.NET站点或任何其他简单站点。内容并不重要。
  2. 使用下面的代码创建一个控制台程序,该代码使用更新的Azure存储API。编译它以进行发布,然后将可执行文件和所有必需的DLL压缩成.zip文件。
  3. 创建一个WebJob并从步骤#2上传.zip文件。 enter image description here
  4. 运行WebJob。写入控制台的所有内容都可以在创建的日志文件中查看,并可从WebJob控制页面访问。
  5. 请注意UpdateAzureServiceVersion方法。显然,默认情况下,Azure存储提供格式不正确的ETag,因此您可能希望运行此代码一次,有关详细信息,请参阅:this
  6. 下面的代码为每个容器运行一个单独的任务,我每个容器每秒更新大约70个标头。没有出口费用。

    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Auth;
    using Microsoft.WindowsAzure.Storage.Blob;
    
    namespace AzureHeaders
    {
        class Program
        {
            static StorageCredentials storageCredentials =
                new StorageCredentials("azureaccountname", @"azzureaccountkey");
            private static string newCacheSettings = "public, max-age=7776000"; // 3 months
            private static string[] containersToProcess = { "container1", "container2" };
    
            static void Main(string[] args)
            {
                var account = new CloudStorageAccount(
                    storageCredentials,
                    false /* useHttps */);
    
                CloudBlobClient blobClient = account.CreateCloudBlobClient();
    
                var tasks = new List<Task>();
                foreach (var container in blobClient.ListContainers())
                {
                    if (containersToProcess.Contains(container.Name))
                    {
                        var c = container;
                        tasks.Add(Task.Run(() => FixHeaders(c)));
                    }
                }
                Task.WaitAll(tasks.ToArray());
            }
    
            private static async Task FixHeaders(CloudBlobContainer cloudBlobContainer)
            {
                int totalCount = 0, updateCount = 0, errorCount = 0;
    
                Console.WriteLine("Starting container: " + cloudBlobContainer.Name);
                IEnumerable<IListBlobItem> blobInfos = cloudBlobContainer.ListBlobs(useFlatBlobListing: true);
    
                foreach (var blobInfo in blobInfos)
                {
                    try
                    {
                        CloudBlockBlob blockBlob = (CloudBlockBlob)blobInfo;
                        var blob = await cloudBlobContainer.GetBlobReferenceFromServerAsync(blockBlob.Name);
                        blob.FetchAttributes();
    
                        // set cache-control header if necessary
                        if (blob.Properties.CacheControl != newCacheSettings)
                        {
                            blob.Properties.CacheControl = newCacheSettings;
                            blob.SetProperties();
                            updateCount++;
                        }
                    }
                    catch (Exception ex)
                    {
                        // Console.WriteLine(ex.Message);
                        errorCount++;
                    }
                    totalCount++;
                }
                Console.WriteLine("Finished container: " + cloudBlobContainer.Name + 
                    ", TotalCount = " + totalCount + 
                    ", Updated = " + updateCount + 
                    ", Errors = " + errorCount);
            }
    
            // http://geekswithblogs.net/EltonStoneman/archive/2014/10/09/configure-azure-storage-to-return-proper-response-headers-for-blob.aspx
            private static void UpdateAzureServiceVersion(CloudBlobClient blobClient)
            {
                var props = blobClient.GetServiceProperties();
                props.DefaultServiceVersion = "2014-02-14";
                blobClient.SetServiceProperties(props);
            }
        }
    }
    

答案 2 :(得分:5)

最新版本的Cerebrata Cloud Storage Studio,v2011.04.23.00,支持在各个blob对象上设置缓存控制。右键单击blob对象,选择“查看/编辑Blob属性”,然后设置Cache-Control属性的值。 (例如public, max-age=2592000)。

如果使用curl检查blob对象的HTTP标头,您将看到返回的缓存控制标头包含您设置的值。

答案 3 :(得分:3)

答案 4 :(得分:2)

有时,最简单的答案是最好的答案。如果您只想管理少量blob,可以使用Azure Management更改blob的标头/元数据。

  1. 单击存储,然后单击存储帐户名称。
  2. 单击容器选项卡,然后单击容器。
  3. 点击blob,然后点击屏幕底部的编辑
  4. 在该编辑窗口中,您可以自定义缓存控制内容编码内容语言等。

    注意: 目前无法通过Azure Portal

    编辑此数据

答案 5 :(得分:0)

这可能为时已晚,无法回答,但最近我想以不同的方式做同样的事情,我有图像列表,需要使用powershell脚本进行应用(当然借助Azure存储组件) 希望将来有人会发现这有用。

Set Azure blob cache-control using powershell script

中给出的完整说明
Add-Type -Path "C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.3\ref\Microsoft.WindowsAzure.StorageClient.dll"

$accountName = "[azureaccountname]"
$accountKey = "[azureaccountkey]"
$blobContainerName = "images"

$storageCredentials = New-Object Microsoft.WindowsAzure.StorageCredentialsAccountAndKey -ArgumentList $accountName,$accountKey
$storageAccount = New-Object Microsoft.WindowsAzure.CloudStorageAccount -ArgumentList $storageCredentials,$true
#$blobClient = $storageAccount.CreateCloudBlobClient()
$blobClient =  [Microsoft.WindowsAzure.StorageClient.CloudStorageAccountStorageClientExtensions]::CreateCloudBlobClient($storageAccount)

$cacheControlValue = "public, max-age=604800"

echo "Setting cache control: $cacheControlValue"

Get-Content "imagelist.txt" | foreach {     
    $blobName = "$blobContainerName/$_".Trim()
    echo $blobName
    $blob = $blobClient.GetBlobReference($blobName)
    $blob.Properties.CacheControl = $cacheControlValue
    $blob.SetProperties()
}

答案 6 :(得分:0)

按PowerShell脚本设置存储blob缓存控制属性

https://gallery.technet.microsoft.com/How-to-set-storage-blob-4774aca5

#creat CloudBlobClient 
Add-Type -Path "C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.3\ref\Microsoft.WindowsAzure.StorageClient.dll" 
$storageCredentials = New-Object Microsoft.WindowsAzure.StorageCredentialsAccountAndKey -ArgumentList $StorageName,$StorageKey 
$blobClient =   New-Object Microsoft.WindowsAzure.StorageClient.CloudBlobClient($BlobUri,$storageCredentials) 
#set Properties and Metadata 
$cacheControlValue = "public, max-age=60480" 
foreach ($blob in $blobs) 
{ 
  #set Metadata 
  $blobRef = $blobClient.GetBlobReference($blob.Name) 
  $blobRef.Metadata.Add("abcd","abcd") 
  $blobRef.SetMetadata() 

  #set Properties 
  $blobRef.Properties.CacheControl = $cacheControlValue 
  $blobRef.SetProperties() 
}

答案 7 :(得分:0)

这是Joel Fillmore使用WindowsAzure.Storage v9.3.3的答案的更新版本。请注意,ListBlobsSegmentedAsync返回的页面大小为5,000,这就是使用BlobContinuationToken的原因。

    public async Task BackfillCacheControlAsync()
    {
        var container = await GetCloudBlobContainerAsync();
        BlobContinuationToken continuationToken = null;

        do
        {
            var blobInfos = await container.ListBlobsSegmentedAsync(string.Empty, true, BlobListingDetails.None, null, continuationToken, null, null);
            continuationToken = blobInfos.ContinuationToken;
            foreach (var blobInfo in blobInfos.Results)
            {
                var blockBlob = (CloudBlockBlob)blobInfo;
                var blob = await container.GetBlobReferenceFromServerAsync(blockBlob.Name);
                if (blob.Properties.CacheControl != "public, max-age=31536000")
                {
                    blob.Properties.CacheControl = "public, max-age=31536000";
                    await blob.SetPropertiesAsync();
                }
            }               
        }
        while (continuationToken != null);
    }

    private async Task<CloudBlobContainer> GetCloudBlobContainerAsync()
    {
        var storageAccount = CloudStorageAccount.Parse(_appSettings.AzureStorageConnectionString);
        var blobClient = storageAccount.CreateCloudBlobClient();
        var container = blobClient.GetContainerReference("uploads");
        return container;
    }

答案 8 :(得分:0)

这里是一个批处理/unix 脚本,适用于没有使用 PowerShell 的 Windows 计算机的每个人。以下脚本循环遍历所有 blob,并分别在 blob 上设置 Content-Cache 属性(Cache-Control http 标头)。

不幸的是,没有办法同时在多个 blob 上设置属性,因此这是一项耗时的任务。每个 blob 通常需要大约 1-2 秒。但是,正如 Jay Borseth 指出的那样,如果在与您的存储帐户位于同一数据中心的服务器上运行该过程,则该过程会显着加快。

# Update Azure Blob Storage blob's cache-control headers
# /content-cache properties
# 
# Quite slow, since there is no `az storage blob update-batch`
#
# Created by Jon Tingvold, March 2021
#
#
# If you want progress, you need to install pv:
# >>> brew install pv  # Mac
# >>> sudo apt install pv  # Ubuntu
#

set -e  # exit when any command fails

AZURE_BLOB_CONNECTION_STRING='DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=XXXXXXXXXXXX;AccountKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=='
CONTAINER_NAME=main

BLOB_PREFIX='admin/'
CONTENT_CACHE='max-age=3600'
NUM_RESULTS=10000000  # Defaults to 5000

BLOB_NAMES=$(az storage blob list --connection-string $AZURE_BLOB_CONNECTION_STRING --container-name $CONTAINER_NAME --query '[].name' --output tsv --num-results $NUM_RESULTS --prefix $BLOB_PREFIX)
NUMBER_OF_BLOBS=$(echo $BLOB_NAMES | wc -w)

echo "Ask Azure for files in Blob Storage ..."
echo "Set content-cache on $NUMBER_OF_BLOBS blobs ..."

for BLOB_NAME in $BLOB_NAMES
do
  az storage blob update --connection-string $AZURE_BLOB_CONNECTION_STRING --container-name $CONTAINER_NAME --name $BLOB_NAME --content-cache $CONTENT_CACHE > /dev/null;
  echo "$BLOB_NAME"

# If you don't have pv install, uncomment  everything after done
done | cat | pv -pte --line-mode --size $NUMBER_OF_BLOBS > /dev/null