次のステートメントを実行すると
Invoke-RestMethod "https://api.mysite.com/the/endpoint" `
-Body (ConvertTo-Json $data) `
-ContentType "application/json" `
-Headers $DefaultHttpHeaders `
-Method Post
エンドポイントは400 Bad Request
を返します。これにより、PowerShellは次のあまり役に立たないメッセージを表示します。
Invoke-WebRequest:リモートサーバーがエラーを返しました:(400)Bad Request。 At line:1 char:1 + Invoke-WebRequest "https://api.mysite.com/the/endpoint "-Body ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo:InvalidOperation:(System.Net.HttpWebRequest:HttpWebRequest)[Invoke-WebRequest]、WebException + FullyQualifiedErrorId:WebCmdletWebResponseException、Microsoft.PowerShell.Commands.InvokeWebRequestCommand
応答の本文を取得するにはどうすればよいですか?これにより、送信した要求の何が問題なのかがわかりますか?
Invoke-RestMethod ドキュメントによると、コマンドレットは受信するコンテンツに応じて異なるタイプを返すことができます。コマンドレットの出力を変数($resp = Invoke-RestMethod (...)
)に割り当ててから、型がHtmlWebResponseObject
($resp.gettype()
)かどうかを確認します。その後、BaseResponse、Content、StatusCodeなどの多くのプロパティを自由に使用できます。
_$resp
_が他の型(この場合は文字列、psobject、おそらくnull)である場合、エラーメッセージThe remote server returned an error: (400) Bad Request
は応答本体であり、htmlからのみ削除されているようです(一部でこれをテストしました私の方法の)、おそらく切り捨てられます。抽出する場合は、共通パラメーターを使用してコマンドレットを実行し、エラーメッセージInvoke-RestMethod (...) -ErrorVariable RespErr
を保存すると、_$RespErr
_変数に格納されます。
編集:
わかりました、私はそれを得て、それはかなり明白でした:)。 Invoke-RestMethodはエラーをスローするため、キャッチするだけです。
_try{$restp=Invoke-RestMethod (...)} catch {$err=$_.Exception}
$err | Get-Member -MemberType Property
TypeName: System.Net.WebException
Name MemberType Definition
---- ---------- ----------
Message Property string Message {get;}
Response Property System.Net.WebResponse Response {get;}
Status Property System.Net.WebExceptionStatus Status {get;}
_
特にWebResponseオブジェクトで必要なものはすべてここにあります。目を引く3つのプロパティをリストしましたが、それ以外にもあります。また、_$_
_の代わりに_$_.Exception
_を保存する場合、PowerShellが既に抽出されたプロパティがある可能性がありますが、_.Exception.Response
_ほど意味のあるものは期待していません。
PowerShell _Invoke-WebRequest
_および_Invoke-RestMethod
_には、ステータスコードがエラー(4xxまたは5xx)の場合にシェルが応答本文を食べるという既知の問題があります。探しているJSONコンテンツはまさにこの方法で蒸発しているように聞こえます。 $_.Exception.Response.GetResponseStream()
を使用して、catchブロックで応答本文を取得できます。
_ try {
Invoke-RestMethod "https://api.mysite.com/the/endpoint" `
-Body (ConvertTo-Json $data) `
-ContentType "application/json" `
-Headers $DefaultHttpHeaders `
-Method Post
}
catch {
$streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
$ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json
$streamReader.Close()
}
$ErrResp
_
$ RespErrには、私の場合、BadRequestの詳細が含まれます。
$responce = Invoke-RestMethod -Uri https://localhost:44377/explore/v2/Content -Method Post -Body $PostData -Headers $header -ErrorVariable RespErr;
$ RespErr;
{ "error":{ "code":"","message":"The FavoriteName field is required." } }
ローカルホストでのみ動作するようです。実際のサーバーで試してみましたが、動作しませんでした。
別の方法はこれです
try{
$response = ""
$response = Invoke-WebRequest -Uri https://contentserverint-mhdev.azurewebsites.net/apis/explore/v2/Content?overwrite=true -Method Post -Body $PostData -Headers $header -ErrorVariable RespErr
#$response = Invoke-RestMethod -Uri https://localhost:44377/explore/v2/Content?overwrite=true -Method Post -Body $PostData -Headers $header -ErrorVariable RespErr
Write-Host "Content created with url="$response.value[0]
}
catch [System.Net.WebException] {
$respStream = $_.Exception.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($respStream)
$respBody = $reader.ReadToEnd() | ConvertFrom-Json
$respBody;
}
応答StatusCode
とContent
の直後にいる場合は、面倒なtry/catchや応答ストリームの手動読み取りなしでこの問題を解決する新しい方法があります。
_# Place the trap within your chosen scope (e.g. function or script)
trap [Net.WebException] { continue; }
# Exceptions are no longer thrown here
$response = Invoke-WebRequest $endpoint
# Check if last command failed
if (!$?)
{
# $error[0] now contains the ErrorRecord of the last error (in this case from Invoke-WebRequest)
# Note: $response should be null at this point
# Due to the magic of Microsoft.PowerShell.Commands.InvokeWebRequestCommand.WebCmdletWebResponseException
# we can get the response body directly from the ErrorDetails field
$body = $error[0].ErrorDetails.Message
# For compatibility with $response.StatusCode lets cast to int
$statusCode = [int] $error[0].Exception.Response.StatusCode
}
_
私の知る限り、_ErrorRecord.ErrorDetails.Message
_には_Microsoft.PowerShell.Commands.WebResponseObject.Content
_プロパティとまったく同じものが含まれており、_Invoke-WebRequest
_の呼び出しが成功すると返されます。すべてのGetResponseStream()
jazz。
私にとって、それは読む前にストリームの位置を0に設定するとき、Pesterコンテキストでのみ機能しました。
$statusCode = $null
$responseBody = $null
try {
$response = Invoke-RestMethod -Method GET -Uri "$($apiPrefix)$($operation)" -Headers $headers
}
catch [System.Net.WebException] {
$statusCode = $_.Exception.Response.StatusCode
$respStream = $_.Exception.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($respStream)
$reader.BaseStream.Position = 0
$responseBody = $reader.ReadToEnd() | ConvertFrom-Json
}
$statusCode | Should Be $Expected
$responseBody | Should Not Be $null