Как заставить Powershell Invoke-Restmethod возвращать тело ответа HTTP 500
Вызов Invoke-RestMethod возвращает только очень бесполезное исключение ниже и не (насколько я могу судить) позволяет собирать содержимое тела (объект JSON, показанный в результатах трассировки фиддлера). Это кажется довольно плохой реализацией, если так, потому что определение http 500 довольно конкретно, что клиент должен возвращать тело ответа, чтобы помочь устранить неполадки... Я что-то упустил?
invoke-restmethod -method Post -uri "https://api-stage.enviance.com/ver2/EqlService.svc/eql" -Body (ConvertTo-Json $eqlhash) -Headers @{"Authorization"="Enviance $session"}
invoke-restmethod: удаленный сервер возвратил ошибку: (500) Internal Server Error. В строке:1 символ:9...
След скрипача ниже
HTTP/1.1 500 Внутренняя ошибка сервера Подключение: закрыть Дата: четверг, 12 сентября 2013 г., 17:35:00 GMT Сервер: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 EnvApi- Версия: 2.0,2.0 EnvApi-Remaining-Calls: 994,994 EnvApi-Remaining-Interval: 2684,2684 Cache-Control: без кеш-памяти Pragma: no-cache Истекает: -1 Content-Type: text/csv; кодировка = UTF-8
{"errorNumber": 0, "message": "Текущий пользователь не имеет прав на получение данных из таблицы 'CustomFieldTemplate'"}
8 ответов
Хотя это старый поток, здесь ответ на проблему с командлетами Invoke-WebRequest и Invoke-RestMethod.
Этот беспокоил меня довольно долго. Поскольку все ответы 4xx и 5xx генерируют исключение, вы должны его перехватить, и тогда вы сможете извлечь ответ оттуда. Используйте это так:
$resp = try { Invoke-WebRequest ... } catch { $_.Exception.Response }
Теперь $resp всегда содержит все, что вам нравится.
Другой ответ действительно дает вам ответ, но вам нужен дополнительный шаг, чтобы получить фактическое тело ответа, а не только заголовки. Вот фрагмент:
try {
$result = Invoke-WebRequest ...
}
catch {
$result = $_.Exception.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($result)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
}
Это решение больше не работает с PowerShell 6 - оно не поддерживает GetResponseStream()
, Вместо этого используйте
try {
$result = Invoke-WebRequest ...
}
catch {
$_.ErrorDetails.Message
}
Я написал короткую вспомогательную функцию для поддержки PowerShell 6 и более ранних версий:
function ParseErrorForResponseBody($Error) {
if ($PSVersionTable.PSVersion.Major -lt 6) {
if ($Error.Exception.Response) {
$Reader = New-Object System.IO.StreamReader($Error.Exception.Response.GetResponseStream())
$Reader.BaseStream.Position = 0
$Reader.DiscardBufferedData()
$ResponseBody = $Reader.ReadToEnd()
if ($ResponseBody.StartsWith('{')) {
$ResponseBody = $ResponseBody | ConvertFrom-Json
}
return $ResponseBody
}
}
else {
return $Error.ErrorDetails.Message
}
}
try {
$result = Invoke-WebRequest ...
}
catch {
ParseErrorForResponseBody($_)
}
В поисках ответа на мою проблему я нашел эту тему.
Эти решения работали для меня, но мне пришлось добавить две новые строки:
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
Спасибо!
Я использовал исключительно Invoke-RestMethod - и, поскольку это может быть оболочка для Invoke-WebRequest, следующая информация может быть полезной.
Вам нужно перехватить исключение, а затем получить поток ответа от Response вот так.
try
{
$response = Invoke-RestMethod Method Get uri "$($uri)" -Headers $headers
return $response
}
catch
{
Write-Host "Exception details: "
$e = $_.Exception
Write-Host ("`tMessage: " + $e.Message)
Write-Host ("`tStatus code: " + $e.Response.StatusCode)
Write-Host ("`tStatus description: " + $e.Response.StatusDescription)
Write-Host "`tResponse: " -NoNewline
$memStream = $e.Response.GetResponseStream()
$readStream = New-Object System.IO.StreamReader($memStream)
while ($readStream.Peek() -ne -1) {
Write-Host $readStream.ReadLine()
}
$readStream.Dispose();
}
Обратите внимание, что в качестве дополнения к поставщику ответов Florial Feldhaus $_.ErrorDetails.Message
не является исходным телом ответа. Регулярное выражение удаления HTML-тега используется для облегчения чтения ответа на github-ссылке. Поскольку поток расположен на линии 1535, в настоящее время нет способа извлечь исходное тело ответа.
Обходной путь заключается в использовании dotnet HttpClient
чтобы получить исходный ответ вместо использования Invoke-WebRequest
командлет
$url = "http://localhost"
$client = [System.Net.Http.HttpClient]::new()
$request = [System.Net.Http.HttpRequestMessage]::new()
$request.Content = [System.Net.Http.StringContent]::new("Hello World", [System.Text.Encoding]::UTF8, "plain/text")
$result = $client.SendAsync($request).GetAwaiter().GetResult()
$content = $result.Content.ReadAsStringAsync().GetAwaiter().GetResult()
Write-Verbose $content -Verbose
Ядро PowerShell Github здесь
Поскольку это одно из первых попаданий в Google, вот ответ для powershell core 6.0.0/7.0.0.
Invoke-RestMethod и Invoke-WebRequest поддерживает-SkipHttpErrorCheck
выключатель:
Этот параметр заставляет командлет игнорировать состояния ошибок HTTP и продолжать обработку ответов. Ответы на ошибки записываются в конвейер так же, как если бы они были успешными.
Если используется этот переключатель, командлеты не выдают ошибку при получении кода состояния сбоя.
Также Invoke-RestMethod теперь имеет параметры командной строки.-StatusCodeVariable
и это можно использовать для извлечения и сохранения кода состояния ответа и заголовков
-ResponseHeadersVariable
был добавлен в v6.0.0 и-SkipHttpErrorCheck/ResponseStatusVariable
на версии 7.0.0
Улучшенная встроенная обработка теперь (?)
Я использую Powershell 7.3.9 в Linux и 5.1.19041.3570 в Windows и обнаружил, что тело ответа теперь отображается в сообщении об ошибке. Поэтому я удалил дополнительную обработку исключений и позволил поведению по умолчанию взять верх.