如何获取从Invoke-RestMethod返回400 Bad Request的Web请求的正文

Tom*_*han 28 rest powershell

当我运行以下语句时

Invoke-RestMethod "https://api.mysite.com/the/endpoint" `
    -Body (ConvertTo-Json $data) `
    -ContentType "application/json" `
    -Headers $DefaultHttpHeaders `
    -Method Post
Run Code Online (Sandbox Code Playgroud)

端点返回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

我如何获得响应的正文,这可能告诉我发送的请求有什么问题?

小智 28

有使用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
Run Code Online (Sandbox Code Playgroud)

  • 我赞同@srsedate 所说的。我必须把 `$streamReader.BaseStream.Position = 0` (4认同)
  • 我想指出的是,对我来说,在调用“ReadToEnd()”之前,我必须明确将“StreamReader”的属性“BaseStream.Position”设置为“0”。 (3认同)
  • 您是否有机会链接到“PowerShell 存在已知问题”的某种参考和更多详细信息,以便我们可以判断它是否已修复? (3认同)
  • 感谢您试图帮我搞定!最后一个命令在Windows 2012 Server VM上输出460805,我正在尝试运行它.当我尝试显示"new"的重载时,它不会生成任何输出.在我的本地Windows 10计算机上,您的示例工作正常,因此我放弃了在服务器上使用它.我最终在"catch"块中使用了这一行,只是为了向主机发送错误消息:``Write-Error("ERROR发生:$($ _.Exception.Message)`r`n"+"响应体:`r`n $($ _.ToString())")`` (2认同)
  • 是的,这应该标记为答案。谢谢你。 (2认同)

Ada*_*ski 11

根据Invoke-RestMethod文档,cmdlet可以根据收到的内容返回不同的类型.将cmdlet输出分配给变量($resp = Invoke-RestMethod (...)),然后检查类型是否为HtmlWebResponseObject($resp.gettype()).然后,您将拥有许多可供您使用的属性,例如BaseResponse,Content和StatusCode.

如果$resp是其他类型(字符串,psobject,在这种情况下很可能为null),似乎错误消息The remote server returned an error: (400) Bad Request是响应主体,只从html中剥离(我在我的一些方法上测试过这个),甚至可能被截断.如果要提取它,请使用common参数运行cmdlet以存储错误消息: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;}
Run Code Online (Sandbox Code Playgroud)

这就是您所需要的一切,尤其是在WebResponse对象中.我列出了3个引人注目的属性,还有更多.此外,如果您存储$_而不是$_.Exception可能有一些属性PowerShell已经为您提取,但我不期望没有任何更有意义的.Exception.Response.

  • 谢谢 - 使用 `-ErrorVariable` 我能够获得更多信息,但不多。最终,我求助于 Postman 并复制了请求,并获得了更完整的图片;响应的主体是一个 JSON 对象,带有一个 `ErrorMessage`(一个字符串)和一个 `Errors`(一个更具体的消息列表),它们都没有显示在 `-ErrorVariable` 中。有没有办法在 Powershell 中获取失败请求的响应正文? (2认同)
  • `$_.Exception.Response` 缺少响应的正文/内容。当我拿回 400 时,我知道身体将 json 还给我。响应甚至说它是 json (`ContentType : application/json`); 然而,内容长度令人沮丧(`ContentLength : -1`)。我很坚持,但 json 被 PowerShell 删除了。在 Win10 Pro 上通过 v5.0 测试。:( (2认同)

shy*_*am_ 10

在我的情况下,$RespErr 将提供有关 BadRequest 的更多详细信息

$responce = Invoke-RestMethod -Uri https://localhost:44377/explore/v2/Content -Method Post -Body $PostData -Headers $header -ErrorVariable RespErr;
Run Code Online (Sandbox Code Playgroud)

$RespErr;

{ "error":{ "code":"","message":"The FavoriteName field is required." } }
Run Code Online (Sandbox Code Playgroud)

看起来它只适用于本地主机,我尝试使用我的实际服务器它不起作用。

另一种尝试的方法是这个

    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;
 }
Run Code Online (Sandbox Code Playgroud)


Iva*_*rov 6

无论是 200 还是 400,都可以毫无异常地获得 HTTP 响应:

\n

Powershell 7 推出-SkipHttpErrorCheck

\n

它适用于Invoke-WebRequestInvoke-RestMethod

\n
PS> $res = Invoke-WebRequest -SkipHttpErrorCheck -Method POST https://login.microsoftonline.com/does-not-exist/oauth2/token\nPS> $res    \n                                                                                                                                                                                                                                                          \nStatusCode        : 400                                                                                                                  \nStatusDescription : BadRequest                                                                                                           \nContent           : {"error":"invalid_request","error_description":"AADSTS900144: The request body must contain the following parameter:\n                     \'grant_type\'.\\r\\nTrace ID: f40877fd-ae34-4b95-a8d4-c7b8ba613801\\r\\nCorrelation ID: \xe2\x80\xa6\nRawContent        : HTTP/1.1 400 BadRequest\n                    Cache-Control: no-store, no-cache\n                    Pragma: no-cache\n                    Strict-Transport-Security: max-age=31536000; includeSubDomains\n                    X-Content-Type-Options: nosniff\n                    P3P: CP="DSP CUR OTPi IND OTRi\xe2\x80\xa6\nHeaders           : {[Cache-Control, System.String[]], [Pragma, System.String[]], [Strict-Transport-Security, System.String[]], [X-Conte\n                    nt-Type-Options, System.String[]]\xe2\x80\xa6}\nImages            : {}\nInputFields       : {}\nLinks             : {}\nRawContentLength  : 503\nRelationLink      : {}\n
Run Code Online (Sandbox Code Playgroud)\n

MS 文档说:

\n
\n

-跳过HttpErrorCheck

\n
\n

此参数使 cmdlet 忽略 HTTP 错误状态并\n继续处理响应。错误响应被写入\n管道,就像它们成功一样。

\n
\n

  • 这是迄今为止最简单的答案 (2认同)

Kai*_*ter 5

对我来说,它只在 Pester 上下文中工作,在阅读之前将流位置设置为 0 时。

        $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
Run Code Online (Sandbox Code Playgroud)