Azure Billing API 调用返回 404 Error,如何解决?
结论
Subscription ID 拼写错误通常不是问题所在。更常见的情况是,GitHub 示例使用了已经过期的 Billing API 路径或 API 版本,或者接口不适用于当前订阅的计费类型和资源范围。
不要直接复制旧示例中的请求地址。建议使用 Azure Resource Manager 下的 Cost Management API,并逐项确认:
- Azure 环境和 ARM 地址是否正确;
- API 路径与
api-version是否仍受支持; - 订阅是否属于当前登录的租户;
- 调用方是否有权读取成本数据;
- 订阅的计费类型是否支持该接口;
Microsoft.CostManagement或Microsoft.Consumption资源提供程序是否已注册。
为什么会返回 404
Azure Billing、Consumption 和 Cost Management 是几组不同的 API。旧示例可能调用的是历史版本的 Usage API,而目前常用的接口位于以下命名空间:
Microsoft.CostManagement
Microsoft.Consumption
Microsoft.Billing
请求路径、资源范围或 API 版本不匹配时,Azure Resource Manager 通常会返回 404 Not Found。常见响应码包括:
InvalidResourceType
ResourceNotFound
NoRegisteredProviderFound
有些 Azure 接口还会在调用方无权查看目标资源时返回 404,以免暴露资源是否存在。因此,遇到 404 时也要检查权限。
推荐的排查顺序
1. 记录完整请求和响应
不要只看 HTTP 状态码,至少应记录:
- 完整请求 URL,但要隐藏访问令牌;
- HTTP 方法;
api-version;- 响应正文;
x-ms-request-id;x-ms-correlation-request-id。
例如,成本查询接口要求使用 POST,不能使用 GET:
POST https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/query?api-version=2023-03-01
接口路径使用了旧域名、遗漏 /providers/...,或者 HTTP 方法不正确,都可能导致 404。
2023-03-01是 Cost Management Query API 的一个常见版本示例。实际使用前,应根据目标 Azure 环境和官方 API 版本列表确认该版本是否可用。
2. 确认订阅属于当前租户
访问令牌中的租户必须和订阅所属租户一致。可以先通过 ARM 查询订阅:
GET https://management.azure.com/subscriptions/{subscriptionId}?api-version=2020-01-01
Authorization: Bearer {accessToken}
如果这个请求也返回 404,应重点检查:
- 登录时使用的 Tenant ID;
- 服务主体是否位于正确的租户;
- Subscription ID 是否属于该租户;
- 订阅是否已被禁用、转移或删除;
- 是否混用了不同的 Azure 云环境。
公有云通常使用:
https://management.azure.com/
Azure 中国区等主权云使用不同的 ARM 地址和令牌受众,两者不能混用。
3. 检查资源提供程序
先查询注册状态:
az provider show \
--namespace Microsoft.CostManagement \
--query registrationState \
--output tsv
az provider show \
--namespace Microsoft.Consumption \
--query registrationState \
--output tsv
如果尚未注册,可以执行:
az provider register --namespace Microsoft.CostManagement
az provider register --namespace Microsoft.Consumption
注册可能需要一段时间。注册完成后,重新获取访问令牌并再次调用接口。
4. 检查权限和成本数据访问设置
调用方至少需要在目标范围内拥有读取成本数据的权限。常见角色包括:
Cost Management Reader
Reader
Billing Reader
所需角色取决于请求范围:
/subscriptions/{subscriptionId}:检查订阅级 RBAC;/providers/Microsoft.Billing/billingAccounts/...:检查计费账户权限;- 管理组范围:检查管理组权限。
对于 Enterprise Agreement、Microsoft Customer Agreement、合作伙伴管理的订阅或部分间接订阅,可能还要在计费系统中启用费用查看权限。即使调用方有权读取订阅资源,也不一定能查看实际金额。
5. 确认接口与计费类型匹配
Billing Account、Billing Profile 和 Invoice Section 等范围并不是所有订阅都有。下面的路径只适用于支持相应计费层级的账户:
/providers/Microsoft.Billing/billingAccounts/{billingAccountId}
如果误把 Subscription ID 当作 Billing Account ID,通常会收到 404。
如果只是查询某个订阅的成本汇总,可以先使用订阅范围的 Cost Management Query API:
/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/query
如果需要逐条查询用量明细,则应评估 Consumption Usage Details API:
/subscriptions/{subscriptionId}/providers/Microsoft.Consumption/usageDetails
这两个接口的数据结构和使用场景不同。不能只替换路径,然后继续沿用旧的数据模型。
Cost Management Query 调用示例
以下请求用于查询指定时间范围内按天汇总的税前成本:
POST https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/query?api-version=2023-03-01
Authorization: Bearer {accessToken}
Content-Type: application/json
{
"type": "ActualCost",
"timeframe": "Custom",
"timePeriod": {
"from": "2026-08-01T00:00:00Z",
"to": "2026-08-29T23:59:59Z"
},
"dataset": {
"granularity": "Daily",
"aggregation": {
"totalCost": {
"name": "PreTaxCost",
"function": "Sum"
}
}
}
}
C# 示例:
using System.Net.Http.Headers;
using System.Text;
var subscriptionId = "<subscription-id>";
var accessToken = "<access-token>";
var url =
$"https://management.azure.com/subscriptions/{subscriptionId}" +
"/providers/Microsoft.CostManagement/query?api-version=2023-03-01";
var json = """
{
"type": "ActualCost",
"timeframe": "Custom",
"timePeriod": {
"from": "2026-08-01T00:00:00Z",
"to": "2026-08-29T23:59:59Z"
},
"dataset": {
"granularity": "Daily",
"aggregation": {
"totalCost": {
"name": "PreTaxCost",
"function": "Sum"
}
}
}
}
""";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
using var content = new StringContent(
json,
Encoding.UTF8,
"application/json");
using var response = await client.PostAsync(url, content);
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"HTTP {(int)response.StatusCode} {response.StatusCode}");
Console.WriteLine(responseBody);
response.EnsureSuccessStatusCode();
获取令牌时,受众或 scope 必须对应 Azure Resource Manager。使用 Microsoft Identity 客户端库时,公有云通常请求:
https://management.azure.com/.default
如何根据错误正文定位
如果响应中出现:
NoRegisteredProviderFound
一般说明资源提供程序尚未注册,或者指定的 api-version 在当前区域或 Azure 环境中不可用。
如果出现:
ResourceNotFound
应重点检查资源范围、租户和订阅状态,同时确认是否混用了 Subscription ID、Billing Account ID 和 Billing Profile ID。
如果出现:
InvalidResourceType
通常是 API 路径中的 provider 或资源类型有误,常见原因是继续使用了旧示例中的地址。
如果响应没有明确的错误正文,应保留 x-ms-request-id 和请求时间,再通过 Azure 支持渠道查询服务端请求记录。
注意事项
- GitHub 示例可以编译,不等于其中的 API 地址和版本仍然有效。
- 不要用字符串替换的方式将旧 Billing API 强行改成 Cost Management API。请求方法、权限要求和响应模型都可能不同。
- 成本数据通常不会实时生成。新订阅或刚产生的用量可能暂时没有数据,但正常情况下更可能返回空结果,而不是因为”尚无费用”返回 404。
- 不要把服务主体密码、证书和访问令牌写入日志或提交到代码仓库。
- 如果订阅由合作伙伴或其他组织管理,计费账户配置可能会限制成本可见性,此时需要计费管理员授权。
备注:内容仅供参考。
