调用Azure DevTest Labs API时Invoke-RestMethod与Invoke-WebRequest结果差异原因
我尝试调用Azure REST API获取DevTest Labs的调度规则,分别使用Invoke-RestMethod和Invoke-WebRequest发起GET请求,使用的请求URL如下:
普通URL
$url = "https://management.azure.com/subscriptions/{subscriptionID}/resourceGroups/{resourseGroup}/providers/Microsoft.DevTestLab/labs/{LabName}/schedules/LabVmsShutdown?api-version=2018-10-15-preview"
携带$expand参数的URL
$url = "https://management.azure.com/subscriptions/{subscriptionID}/resourceGroups/{resourseGroup}/providers/Microsoft.DevTestLab/labs/{LabName}/schedules/LabVmsShutdown?$expand=properties(dailyRecurrence)&api-version=2018-10-15-preview"
Invoke-RestMethod调用代码及返回结果
$output = Invoke-RestMethod -Uri $url -Method "GET" -ContentType "application/json" -Headers $authHeaders
返回结果:
properties : @{status=Enabled; taskType=LabVmsShutdownTask; dailyRecurrence=; timeZoneId=AUS Eastern Standard Time; notificationSettings=; createdDate=26/03/2019 4:38:18 PM; provisioningState=Succeeded; uniqueIdentifier=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
Invoke-WebRequest调用代码及返回结果
$output = Invoke-WebRequest -Uri $url -Method "GET" -Headers $authHeaders
返回结果:
Content : {"properties":{"status":"Enabled","taskType":"LabVmsShutdownTask","dailyRecurrence":{"time":"1900"} ,"timeZoneId":"AUS Eastern Standard Time","notificationSettings":{"status":"Disabled","timeInMinutes":30},"createdDate":"2019-03-26T03:38:18.0726376+00:00","provisioningState":"Succeeded","uniqueIdentifier":"XXXXXXXXXXXXXXXXXXXXXXXXX"},"id":"/subscriptions/XXXXXXXXXXXXXXXXXXX/resourcegroups/XXXXXXXXXXXXX/providers/microsoft.devtestlab/labs/XXXXXXXX/schedules/labvmsshutdown","name":"LabVmsShutdown","type":"microsoft.devtestlab/labs/schedules","location":"australiasoutheast"}
可以看到Invoke-RestMethod返回结果中dailyRecurrence键没有对应值,而Invoke-WebRequest返回结果中该字段有正常数值,请问造成该差异的原因是什么?
核心原因:JSON反序列化嵌套深度限制
Invoke-RestMethod收到JSON格式的响应后,会自动调用ConvertFrom-Json将字符串反序列化为PowerShell自定义对象(PSCustomObject),而ConvertFrom-Json的默认嵌套解析深度仅为2层。
你需要获取的dailyRecurrence字段属于返回结构的第三层(顶级对象 > properties > dailyRecurrence),超过了默认解析深度,因此反序列化时该属性不会被正确展开,直接显示为空值。
而Invoke-WebRequest不会对响应内容做自动反序列化处理,返回的Content属性就是服务端返回的原始JSON字符串,因此可以看到完整的dailyRecurrence字段值。
次要影响因素:URL参数插值错误
你构造带$expand参数的URL时使用了双引号包裹,PowerShell会将$expand识别为待插值的变量,如果你没有预先定义$expand变量,实际发起请求时URL中的$expand会被替换为空值,导致expand参数失效,无法返回需要的扩展字段内容。
- 构造URL时优先使用单引号包裹,避免PowerShell对$开头的参数做变量插值:
$url = 'https://management.azure.com/subscriptions/{subscriptionID}/resourceGroups/{resourseGroup}/providers/Microsoft.DevTestLab/labs/{LabName}/schedules/LabVmsShutdown?$expand=properties(dailyRecurrence)&api-version=2018-10-15-preview'
- PowerShell 7及以上版本,可以直接给
Invoke-RestMethod添加-Depth参数,设置足够的嵌套解析深度:
$output = Invoke-RestMethod -Uri $url -Method "GET" -ContentType "application/json" -Headers $authHeaders -Depth 10
- PowerShell 5.1及更早版本,
Invoke-RestMethod没有-Depth参数,可以手动处理响应内容:
$webResponse = Invoke-WebRequest -Uri $url -Method "GET" -Headers $authHeaders $parsedObj = $webResponse.Content | ConvertFrom-Json -Depth 10
处理后即可正常获取$parsedObj.properties.dailyRecurrence的完整值。
内容的提问来源于stack exchange,提问作者Smug

