You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Microsoft.WindowsAzure.Storage 9.3.2.0 偶发403 Forbidden问题咨询

问题背景

使用Microsoft.WindowsAzure.Storage(Windows平台Azure存储SDK)9.3.2.0版本实现Blob上传功能,对应C#代码如下:

private class FileBlock
{
    internal string Id { get; set; }
    internal byte[] Content { get; set; }
}
public static async Task<Uri> UploadFileToAzureStorageAsync(string azureStorageUri, string filePath)
{
    var bytes = File.ReadAllBytes(filePath);
    var cloudBlockBlob = new CloudBlockBlob(new Uri(azureStorageUri));
    var blocks = new HashSet<string>();            `enter code here`
    
    try
    {
        foreach (var block in GetFileBlocks(bytes))
        {
            cloudBlockBlob.PutBlock(block.Id, new MemoryStream(block.Content, true), null);
            blocks.Add(block.Id);
        }
        await cloudBlockBlob.PutBlockListAsync(blocks);
    }
    catch (Exception ex)
    {
        Logging.logger.Error(ex);                
    }
    return cloudBlockBlob.Uri;
}
private static IEnumerable<FileBlock> GetFileBlocks(byte[] fileContent)
{
    if (fileContent.Length == 0)
        return new HashSet<FileBlock>();
    var maxBlockSize = 4 * 1024 * 1024;
    var hashSet = new HashSet<FileBlock>();
    var blockId = 0;
    var index = 0;
    var currentBlockSize = maxBlockSize;
    while (currentBlockSize == maxBlockSize)
    {
        if ((index + currentBlockSize) > fileContent.Length)
            currentBlockSize = fileContent.Length - index;
        var chunk = new byte[currentBlockSize];
        Array.Copy(fileContent, index, chunk, 0, currentBlockSize);
        hashSet.Add(new FileBlock
        {
            Content = chunk,
            Id = Convert.ToBase64String(BitConverter.GetBytes(blockId))
        });
        index += currentBlockSize;
        blockId++;
    }
    return hashSet;
}
异常现象

该功能仅在少量包上传时偶发报错,重新触发发布即可上传成功,调整运行机器时区为UTC后问题仍未解决,捕获异常信息如下:

Microsoft.WindowsAzure.Storage.StorageException: The remote server returned an error: (403) Forbidden.
---> System.Net.WebException: The remote server returned an error: (403) Forbidden.
StatusMessage:Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
ErrorCode:AuthenticationFailed
ErrorMessage:Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

根因分析
  1. 客户端与服务端时间偏差过大:Azure存储服务要求请求签名的生成时间和服务端时间偏差不能超过15分钟,仅修改时区为UTC没用,如果机器本地时间和NTP服务器同步不稳定,偶发时间跳变超过阈值就会触发鉴权失败
  2. SAS令牌过期:如果传入的azureStorageUri是带SAS令牌的地址,若SAS有效期设置过短,大文件分块上传耗时超过SAS有效期时,就会出现偶发403,小文件上传快不会触发,重试时新生成的SAS有效就能上传成功
  3. 代码逻辑缺陷:代码中PutBlock使用同步方法,未配置重试策略,网络抖动导致单块上传耗时过长时,后续请求的签名时间超出有效窗口也会触发鉴权失败,且同步异步混用可能导致意料之外的时间延迟
  4. 旧版SDK Bug:Microsoft.WindowsAzure.Storage 9.x版本已经停止维护,存在已知的偶发签名计算错误的问题,高并发场景下更容易出现
解决方案
  • 检查运行机器的NTP时间同步配置,确保机器时间和标准时间偏差控制在5分钟以内,仅调整时区无法解决时间本身不准的问题
  • 若使用SAS令牌鉴权,将SAS的有效期设置为预估最大上传耗时的2倍以上,避免大文件上传过程中SAS过期
  • 优化代码逻辑:将同步PutBlock替换为异步PutBlockAsync并添加await,同时配置请求重试策略,示例配置参考:
var options = new BlobRequestOptions()
{
    RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(2), 5)
};
cloudBlockBlob.ServiceClient.DefaultRequestOptions = options;
  • 升级存储SDK到官方推荐的Azure.Storage.Blobs新版本,旧版SDK的已知签名问题在新版中已修复
  • 必要时开启Azure存储账户的诊断日志,对比失败请求的客户端生成时间和服务端返回的x-ms-date字段,可快速定位是否为时间偏差导致的问题

内容的提问来源于stack exchange,提问作者Sangamesh Gouri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 08:48:03