我使用Azurite在本地运行有关将文件上传到Azure Blob存储的某些功能的测试。我通过使用docker撰写来运行它,并且我想在测试的非默认端口中运行它。我提出的配置如下:
storage:
image: mcr.microsoft.com/azure-storage/azurite
environment:
- AZURITE_ACCOUNTS=account:QUJDRA==
ports:
- "10020:10000"
我使用以下配置在Asp中注册BlobServiceClient
服务。Net核心:
services.AddAzureClients(builder =>
{
builder.AddBlobServiceClient(
new Uri("http://localhost:10020/account"),
new StorageSharedKeyCredential("account", "QUJDRA=="));
});
上传文件的代码如下:
public async Task<string> UploadFile(BlobServiceClient blobServiceClient, Stream file)
{
var blobContainerClient = blobServiceClient.GetBlobContainerClient("container");
await blobContainerClient.CreateIfNotExistsAsync(PublicAccessType.BlobContainer);
var blobClient = blobContainerClient.GetBlobClient("blob");
await blobClient.UploadAsync(file);
return blobClient.Uri.ToString();
}
如果我在默认端口(10000)中运行此配置,则一切正常,并且我从Azurite容器中获得以下日志:
storage-1 | 172.21.0.1 - - [20/Jan/2023:11:02:35 +0000] "PUT /account/container?restype=container HTTP/1.1" 409 -
storage-1 | 172.21.0.1 - - [20/Jan/2023:11:02:37 +0000] "PUT /account/container/blob?comp=block&blockid=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA HTTP/1.1" 201 -
storage-1 | 172.21.0.1 - - [20/Jan/2023:11:02:37 +0000] "PUT /account/container/blob?comp=blocklist HTTP/1.1" 201 -
但是,如果我尝试在非默认端口(10020)中运行它,则上传文件的await blobClient.UploadAsync(file)
行会产生以下异常:
Azure.RequestFailedException : Service request failed.
Status: 400 (Bad Request)
storage-1 | 172.25.0.1 - - [20/Jan/2023:11:18:43 +0000] "PUT /account/container?restype=container HTTP/1.1" 201 -
storage-1 | 172.25.0.1 - - [20/Jan/2023:11:18:44 +0000] "PUT /account/blob?comp=block&blockid=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA HTTP/1.1" 400 -
如果您仔细查看日志的第二行,对应于文件的上传,在这种情况下,url在帐户名之后缺少/container
部分。我想这就是400
错误的原因。
为什么端口的改变会以这种方式改变url ?我还遗漏了什么配置吗?
问题在于BlobContainerClient.GetBlobClient()
如何尝试从Azure.Storage.Blobs(12.14.1)和Azure.Storage.Common(12.13.0)中的URI中确定帐户名称。
GetBlobClient
方法在内部创建BlobUriBuilder
的实例,接收容器客户端的URI。然后它尝试解构URI,但由于帐户名称在Azure存储容器(在域之前)和Azurite(路径的第一部分)中的位置不同,因此端口用于确定应该如何完成。
确定它是否是Azurite实例的白名单端口如下:
10001,10001,10002,10003,10004,
10100,10101, 10102, 10103, 10104,
11000,11001, 11002,11003,11004,
11100,11101, 11102, 11103, 11104
除了源代码,我没有找到任何公开此问题的文档。
来源:BlobUriBuilder
构造函数调用uri.IsHostIPEndPointStyle()
... if (uri.IsHostIPEndPointStyle()) { _isPathStyleUri = true; var accountEndIndex = path.IndexOf("/", StringComparison.InvariantCulture); // Slash not found; path has account name & no container name if (accountEndIndex == -1) { AccountName = path; startIndex = path.Length; } else { AccountName = path.Substring(0, accountEndIndex); startIndex = accountEndIndex + 1; } } else { AccountName = uri.GetAccountNameFromDomain(Constants.Blob.UriSubDomain) ?? string.Empty; } ...
来源:引用Constants.Sas.PathStylePorts
// See remarks at https://docs.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=netframework-4.7.2 /// <summary> /// Check to see if Uri is using IP Endpoint style. /// </summary> /// <param name="uri">The Uri.</param> /// <returns>True if using IP Endpoint style.</returns> public static bool IsHostIPEndPointStyle(this Uri uri) => (!string.IsNullOrEmpty(uri.Host) && uri.Host.IndexOf(".", StringComparison.InvariantCulture) >= 0 && IPAddress.TryParse(uri.Host, out _)) || Constants.Sas.PathStylePorts.Contains(uri.Port);
来源:用于白名单端口
/// <summary> /// List of ports used for path style addressing. /// Copied from Microsoft.Azure.Storage.Core.Util /// </summary> internal static readonly int[] PathStylePorts = { 10000, 10001, 10002, 10003, 10004, 10100, 10101, 10102, 10103, 10104, 11000, 11001, 11002, 11003, 11004, 11100, 11101, 11102, 11103, 11104 };