una solicitud simple peticion permiso pedir para modelos modelo hacer empleo ejemplo documentos cómo carta algo rest powershell

simple - ¿Cómo obtengo el cuerpo de una solicitud web que devolvió 400 solicitudes incorrectas de Invoke-RestMethod



solicitud de permiso (5)

Cuando corro la siguiente sentencia

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

el punto final devuelve 400 Bad Request , lo que hace que PowerShell muestre el siguiente mensaje no tan útil:

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

¿Cómo obtengo el cuerpo de la respuesta, que podría decirme qué problema tenía con la solicitud que envié?


$ RespErr tendrá más detalles sobre la BadRequest en mi caso, su

$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." } }

Parece que funciona solo en localhost, probé con mi servidor real que no funcionó.

Otra forma de probar es esta

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


De acuerdo con la documentación de Invoke-RestMethod , el cmdlet puede devolver diferentes tipos dependiendo del contenido que recibe. Asignar la salida del cmdlet a una variable ( $resp = Invoke-RestMethod (...) ) y luego verificar si el tipo es HtmlWebResponseObject ( $resp.gettype() ). Entonces tendrás muchas propiedades a tu disposición, como BaseResponse, Content y StatusCode.

Si $resp es algún otro tipo (cadena, psobject y probablemente nulo en este caso), parece ser un mensaje de error. The remote server returned an error: (400) Bad Request es el cuerpo de la respuesta, solo eliminado de html (lo probé en algunos de mis métodos), tal vez incluso truncado. Si desea extraerlo, ejecute el cmdlet usando un parámetro común para almacenar el mensaje de error: Invoke-RestMethod (...) -ErrorVariable RespErr y lo tendrá en la variable $RespErr .

EDITAR:

Ok, lo tengo y fue bastante obvio :). Invoke-RestMethod arroja un error, así que simplemente lo detectamos:

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

Aquí está todo lo que necesita, especialmente en el objeto WebResponse. He enumerado 3 propiedades que llaman la atención, hay más. Además, si almacena $_ lugar de $_.Exception , podría haber algunas propiedades que PowerShell ya extrajo para usted, pero no espero nada más significativo que en .Exception.Response .


Hay un problema conocido con PowerShell Invoke-WebRequest y Invoke-RestMethod donde el shell come el cuerpo de la respuesta cuando el código de estado es un error (4xx o 5xx). Parece que el contenido JSON que está buscando se está evaporando de esta manera. Puede obtener el cuerpo de la respuesta en su bloque catch usando $_.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


Para mí, solo funcionó en un contexto de Pester, al establecer la Posición de los flujos en 0 antes de leerlo.

$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


Si está justo después de la respuesta, StatusCode y Content aquí es una forma novedosa de resolver este problema sin muchas pruebas desagradables y lectura manual de las secuencias de respuesta:

# 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 }

Por lo que puedo decir, el ErrorRecord.ErrorDetails.Message contiene el equivalente exacto a la propiedad Microsoft.PowerShell.Commands.WebResponseObject.Content que se le devolvería en una invocación exitosa de Invoke-WebRequest , solo sin la molestia de tener para hacer todo lo que GetResponseStream() jazz.