【问题标题】:How to get Powershell Invoke-Restmethod to return body of http 500 code response如何让 Powershell Invoke-Restmethod 返回 http 500 代码响应的正文
【发布时间】:2013-09-17 06:17:50
【问题描述】:

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) 内部服务器错误。在 line:1 char:9...

下面的提琴手踪迹

HTTP/1.1 500 内部服务器错误连接:关闭日期:9 月 12 日星期四 2013 年 17:35:00 GMT 服务器:Microsoft-IIS/6.0 X-Powered-By:ASP.NET X-AspNet 版本:2.0.50727 EnvApi 版本:2.0,2.0 EnvApi-Remaining-Calls:994,994 EnvApi-Remaining-Interval:2684,2684 Cache-Control: no-cache Pragma: no-cache Expires: -1 Content-Type: 文本/csv;字符集=utf-8

{"errorNumber":0,"message":"当前用户无权检索 表 'CustomFieldTemplate' 中的数据"}

【问题讨论】:

  • invoke-webrequest 中的同样问题
  • “powershell 4.0 中的新增功能表明(可能)此问题是一个错误并已修复。technet.microsoft.com/en-us/library/hh857339.aspx#BKMK_bugs 在值得注意的错误修复部分下:Invoke-RestMethod cmdlet 现在返回所有可用的结果。

标签: powershell powershell-3.0


【解决方案1】:

另一个答案确实为您提供了响应,但您需要一个额外的步骤来获取响应的实际正文,而不仅仅是标题。这是一个sn-p:

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();
}

【讨论】:

    【解决方案2】:

    虽然是旧线程,但这里是 cmdlet Invoke-WebRequest 和 Invoke-RestMethod 问题的答案。

    这个问题困扰了我一段时间。由于所有 4xx 和 5xx 响应都在生成异常,因此您必须捕获该异常,然后才能从那里提取响应。像这样使用它:

    $resp = try { Invoke-WebRequest ... } catch { $_.Exception.Response }
    

    现在 $resp 总是包含你喜欢的一切。

    【讨论】:

    • 可能应该将 -ErrorAction Stop 添加到 Invoke-WebRequest 调用中。
    【解决方案3】:

    此解决方案不再适用于 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($_)
    }
    

    【讨论】:

    • 正是我想要的。谢谢!
    • 完美解决方案。 ` _.Exception.Response` 提供有关 HTTPResponse 的所有详细信息,但不提供确切的错误详细信息。 _.ErrorDetails.Message是完美的错误显示
    • 这似乎累积了以前运行的错误 $Error.ErrorDetails.Message
    • PowerShell 确实使用$Error 作为变量来提供最近的异常列表。由于该函数使用嵌套范围,这仍然很好,并且解决方案可以正常工作。如果需要,请将变量 $Error 重命名为 $Err 以避免混淆。为了更好的可读性,我保留了它。
    【解决方案4】:

    搜索我的问题的答案,我找到了这个帖子。

    这些解决方案对我有用,但我必须添加两个新行:

     $reader.BaseStream.Position = 0
     $reader.DiscardBufferedData()
    

    谢谢!

    【讨论】:

    • 我也必须这样做,我在 $responseBody = $reader.ReadToEnd(); 之前添加了这些行;
    【解决方案5】:

    我一直在专门使用 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();
        }
    

    参考:https://social.technet.microsoft.com/Forums/windowsserver/en-US/7d838d53-bfd5-4706-b0df-c4bee2d00412/using-memorystream-and-textreader

    【讨论】:

    • 它非常适合我。我唯一的改变是在 "Write-Host ("`tStatus code: " + $e.Response.StatusCode)" 行...我将 ".value__" 添加到 "$e.Response.StatusCode)": "$e .Response.StatusCode.value__" 用于获取状态码号
    【解决方案6】:

    请注意,作为 Florial Feldhaus 对答案提供者的扩展,$_.ErrorDetails.Message 不是原始响应正文。 HTML 标记删除正则表达式用于使响应更易于阅读github link。由于流是在第 1535 行处理的,因此目前无法检索原始响应正文。

    解决方法是使用 dotnet HttpClient 来获取原始响应,而不是使用 Invoke-WebRequest cmdlet

    $url = "http://localhost"
    $client = [System.Net.Http.HttpClient]::new()
    $request = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::Post, $url)
    $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问题是here

    【讨论】:

    • 此响应存在一些问题,除非其意图是提供 PowerShell 6/Core 答案。 1) 如果不先加载 System.Net.Http.dll 程序集类,这在 PowerShell 5.x 中不起作用:例如。 [void][System.Reflection.Assembly]::LoadFile("C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Net.Http.dll") 2)* 第 3 行缺少 [System.Net.Http.HttpRequestMessage]::new() 构造函数中的 $url 变量。 3) 第 4 行将在 PowerShell 5.x 中生成带有[System.Net.Http.HttpMethod]::GET 动词的异常。
    猜你喜欢
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多