PowerShell:从 JSON 响应中提取单个值
结论
$Result.Content 是 JSON 字符串。先用 ConvertFrom-Json 将它转换为 PowerShell 对象,再通过属性路径读取 transaction.id、transaction.status 和 transaction.amount,不需要使用 Substring。
$response = $Result.Content | ConvertFrom-Json
$transactionId = $response.transaction.id
$transactionStatus = $response.transaction.status
$transactionAmount = $response.transaction.amount
为什么不能直接读取字段
Invoke-WebRequest 返回一个响应对象,其中:
$Result.StatusCode是 HTTP 状态码。$Result.StatusDescription是 HTTP 状态说明。$Result.Content是响应正文。
即使响应正文采用 JSON 格式,$Result.Content 通常仍然是字符串。PowerShell 不会自动把字符串中的 JSON 字段转换成对象属性,所以不能这样读取:
$Result.Content.transaction.id
ConvertFrom-Json 可以把 JSON 对象转换成 PowerShell 对象,同时保留嵌套结构。
提取响应字段
在调用 Invoke-WebRequest 后解析响应:
$Result = Invoke-WebRequest `
-Uri $Uri `
-ContentType 'multipart/form-data' `
-Method Post `
-Headers $headers `
-Body $body
$response = $Result.Content | ConvertFrom-Json
$transaction = $response.transaction
$transactionId = $transaction.id
$processedAt = $transaction.processed_at
$transactionType = $transaction.transaction_type
$currencyCode = $transaction.currency_code
$transactionAmount = $transaction.amount
$recipientId = $transaction.recipient_id
$transactionStatus = $transaction.status
$transactionStatusInfo = $transaction.status_info
$reference = $transaction.reference
$accountId = $transaction.account_id
Write-Host "Transaction ID: $transactionId"
Write-Host "Status: $transactionStatus"
Write-Host "Amount: $transactionAmount"
按照题目中的响应,输出内容类似:
Transaction ID: 83123b05-2435-40c9-851d-a5636f092637
Status: Waiting for funds
Amount: 25000
如果只读取一个字段,可以直接写成:
$transactionId = ($Result.Content | ConvertFrom-Json).transaction.id
如果需要读取多个字段,最好只解析一次 JSON,避免重复调用 ConvertFrom-Json。
使用 Invoke-RestMethod 简化处理
接口返回标准 JSON 时,也可以用 Invoke-RestMethod 代替 Invoke-WebRequest。Invoke-RestMethod 通常会根据响应的 Content-Type 自动解析 JSON:
$response = Invoke-RestMethod `
-Uri $Uri `
-ContentType 'multipart/form-data' `
-Method Post `
-Headers $headers `
-Body $body
$transactionId = $response.transaction.id
$transactionStatus = $response.transaction.status
$transactionAmount = $response.transaction.amount
如果只关心接口返回的数据,这种写法更简洁。
需要注意的是,Invoke-RestMethod 主要返回解析后的响应正文,不像 Invoke-WebRequest 那样便于获取完整的 HTTP 响应信息。如果现有代码还要读取 $Result.StatusCode 或 $Result.StatusDescription,继续使用 Invoke-WebRequest,再手动调用 ConvertFrom-Json 会更清楚。
在现有代码中使用
可以把原来的:
$Result.Content
替换成:
try {
$response = $Result.Content | ConvertFrom-Json
$transaction = $response.transaction
$transactionId = $transaction.id
$transactionStatus = $transaction.status
$transactionAmount = $transaction.amount
Write-Host "Transaction ID: $transactionId"
Write-Host "Transaction status: $transactionStatus"
Write-Host "Transaction amount: $transactionAmount"
}
catch {
Write-Error "无法解析接口返回的 JSON:$($_.Exception.Message)"
}
判断请求是否成功时,比较数值状态码通常比比较状态说明更可靠:
if ($Result.StatusCode -ge 200 -and $Result.StatusCode -lt 300) {
Write-Host "Payment sent successfully" -ForegroundColor Green
}
else {
Write-Host "Payment failed" -ForegroundColor Red
}
不过,Invoke-WebRequest 遇到许多非成功 HTTP 状态码时会直接抛出异常。因此,更完整的做法是把请求也放进 try/catch:
try {
$Result = Invoke-WebRequest `
-Uri $Uri `
-ContentType 'multipart/form-data' `
-Method Post `
-Headers $headers `
-Body $body `
-ErrorAction Stop
$response = $Result.Content | ConvertFrom-Json
$transaction = $response.transaction
$transactionId = $transaction.id
$transactionStatus = $transaction.status
$transactionAmount = $transaction.amount
Write-Host "Payment sent successfully" -ForegroundColor Green
}
catch {
Write-Host "Payment failed: $($_.Exception.Message)" -ForegroundColor Red
}
插入 SQL 时的注意事项
不要把提取出的值直接拼接到 SQL 字符串中。应使用参数化 SQL,以免引号、特殊字符或 SQL 注入造成问题。下面只展示字段绑定方式,连接字符串和表名需要根据实际环境调整:
$command.CommandText = @"
INSERT INTO PaymentTransactions
(TransactionId, Status, Amount)
VALUES
(@TransactionId, @Status, @Amount)
"@
$null = $command.Parameters.AddWithValue(
"@TransactionId",
[Guid]$transactionId
)
$null = $command.Parameters.AddWithValue(
"@Status",
[string]$transactionStatus
)
$null = $command.Parameters.AddWithValue(
"@Amount",
[decimal]$transactionAmount
)
还要注意:
- JSON 中的
amount是数字,解析后不需要再从字符串中截取。 processed_at等时间字段如果要写入日期列,建议显式转换为[DateTimeOffset]。reconciliation、tag和end_balance等字段可能为null,写入数据库时可能需要转换成[DBNull]::Value。- 读取属性前,应先确认
$response.transaction确实存在。 - 示例响应中的金额是
25000,但仅凭响应无法判断它表示25000 GBP,还是以便士等最小货币单位计价。写入数据库前,应以接口约定为准。
备注:内容仅供参考。
