当我运行以下声明时
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
如何获取响应的正文,这可能会告诉我发送的请求有什么问题?
答案 0 :(得分:18)
PowerShell Invoke-WebRequest
和Invoke-RestMethod
存在一个已知问题,当状态代码为错误(4xx或5xx)时,shell会占用响应正文。听起来像你正在寻找的JSON内容正在以这种方式蒸发。您可以使用$_.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
答案 1 :(得分:9)
根据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;}
这就是您所需要的一切,尤其是在WebResponse对象中。
我列出了3个引人注目的属性,还有更多。此外,如果您存储$_
而不是$_.Exception
,PowerShell可能会为您提取一些属性,但我不希望在.Exception.Response
中有任何更有意义的内容。
答案 2 :(得分:4)
$ 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;
}
答案 3 :(得分:1)
如果您刚刚回复StatusCode
和Content
,这是一种解决此问题的新方法,没有大量凌乱的尝试/捕获和手动读取响应流:
# 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()
爵士乐。
答案 4 :(得分:1)
对我来说,它仅在Pester上下文中有效,当在读取之前将流Position设置为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
答案 5 :(得分:1)
从服务器发送的文本响应包含在以下位置的error变量中:
<my_entity_name>
答案 6 :(得分:0)
无论200还是400,您都可以无一例外地获得HTTP响应:
Powershell 7推出了-SkipHttpErrorCheck
?
它同时适用于Invoke-WebRequest
和Invoke-RestMethod
:
PS> $res = Invoke-WebRequest -SkipHttpErrorCheck -Method POST https://login.microsoftonline.com/does-not-exist/oauth2/token
PS> $res
StatusCode : 400
StatusDescription : BadRequest
Content : {"error":"invalid_request","error_description":"AADSTS900144: The request body must contain the following parameter:
'grant_type'.\r\nTrace ID: f40877fd-ae34-4b95-a8d4-c7b8ba613801\r\nCorrelation ID: …
RawContent : HTTP/1.1 400 BadRequest
Cache-Control: no-store, no-cache
Pragma: no-cache
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
P3P: CP="DSP CUR OTPi IND OTRi…
Headers : {[Cache-Control, System.String[]], [Pragma, System.String[]], [Strict-Transport-Security, System.String[]], [X-Conte
nt-Type-Options, System.String[]]…}
Images : {}
InputFields : {}
Links : {}
RawContentLength : 503
RelationLink : {}
-SkipHttpErrorCheck
此参数使cmdlet忽略HTTP错误状态,并且 继续处理回应。错误响应将写入 就好像他们成功一样。