Как получить тело веб-запроса, которое возвратило 400 Bad Request из Invoke-RestMethod
Когда я запускаю следующую инструкцию
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 : The remote server returned an error: (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
Как получить тело ответа, которое может сказать мне, что было не так с запросом, который я отправил?
Ответы
Ответ 1
Согласно документации Invoke-RestMethod, командлет может возвращать разные типы в зависимости от получаемого контента. Вывод команды cmdlet в переменную ($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
.
EDIT:
Хорошо, я понял, и это было довольно очевидно:). 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
.
Ответ 2
Известна проблема с PowerShell Invoke-WebRequest
и Invoke-RestMethod
, где оболочка ест тело ответа, когда код состояния является ошибкой (4xx или 5xx). Похоже, что контент JSON, который вы ищете, испаряется именно таким образом. Вы можете получить тело ответа в блоке catch с помощью $_.Exception.Response.GetResponseStream()
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
Ответ 3
$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." } }
Похоже, что он работает только в localhost, я пытался с моим фактическим сервером, что он не работал.
Другой способ попробовать - это
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;
}