PAYATHON 2026

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,还是以便士等最小货币单位计价。写入数据库前,应以接口约定为准。

备注:内容仅供参考。