2016-03-14 31 views
12

Quando eseguo la seguente dichiarazioneCome faccio ad avere il corpo di una richiesta Web che ha restituito 400 Bad Request da Invoke-RestMethod

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

l'endpoint restituisce 400 Bad Request, che provoca PowerShell per mostrare la seguente non-così messaggio -helpful:

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

Come faccio ad avere il corpo della risposta, che mi potrebbe dire cosa non andava con la richiesta che ho inviato?

+1

Forse il server dovrebbe essere fissata: '200 OK' '* o * 400 Bad request'. –

+0

@LutzHorn: In questo caso so che è la mia chiamata API che non è corretta. Non so esattamente * perché *. –

+0

Siamo spiacenti, la '200 Richiesta non valida 'era un errore di battitura; dovrebbe essere '400 Bad Request'. La dichiarazione nel mio codice attuale non ha interruzioni di linea, come affermato. –

risposta

6

In base alla documentazione Invoke-RestMethod, il cmdlet può restituire diversi tipi a seconda del contenuto ricevuto. Assegnare l'output del cmdlet a una variabile ($resp = Invoke-RestMethod (...)) e quindi verificare se il tipo è HtmlWebResponseObject ($resp.gettype()). Quindi avrai a disposizione molte proprietà, come BaseResponse, Content e StatusCode.

Se $resp è un altro tipo (stringa, psobject e molto probabilmente null in questo caso), sembra che il messaggio di errore The remote server returned an error: (400) Bad Request sia il corpo della risposta, solo rimosso da html (l'ho provato su alcuni dei miei metodi), forse persino troncato. Se desideri estrarlo, esegui il cmdlet utilizzando il parametro comune per archiviare il messaggio di errore: Invoke-RestMethod (...) -ErrorVariable RespErr e lo avrai nella variabile $RespErr.

EDIT:

Ok, ho capito ed era abbastanza ovvio :). Invoke-RestMethod genera un errore, così lascia solo prenderlo:

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

Ecco tutto ciò che serve, soprattutto in oggetto WebResponse. Ho elencato 3 proprietà che catturano l'attenzione, c'è di più. Inoltre, se si memorizza $_ anziché $_.Exception, è possibile che alcune proprietà PowerShell siano già state estratte per l'utente, ma non mi aspetto nulla di più significativo rispetto a .Exception.Response.

+0

Grazie - usando '-ErrorVariable' sono riuscito a ottenere un po 'di informazioni in più, ma non molto.Alla fine ho fatto ricorso a Postman e ho replicato la richiesta, ottenendo un'immagine più completa; il corpo della risposta è un oggetto JSON con un 'ErrorMessage' (una stringa) e' Errors' (una lista di messaggi più specifici), nessuno dei quali è stato mostrato in '-ErrorVariable'. Non c'è modo di ottenere il corpo della risposta per richieste fallite all'interno di PowerShell? –

+0

@TomasLycken Dopo tutto c'è un modo, guarda la modifica. –

+0

Grazie mille per la tua persistenza! Sicuramente vale alcuni punti, eh? :) –

7

C'è un problema noto con PowerShell Invoke-WebRequest e Invoke-RestMethod in cui la shell mangia il corpo della risposta quando il codice di stato è un errore (4xx o 5xx). Sembra che il contenuto JSON che stai cercando stia evaporando proprio in questo modo. È possibile recuperare il corpo della risposta nel blocco catch utilizzando $_.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 
+0

Questo sembra ottimo, ma genera un'eccezione per me: "Invocazione del metodo non riuscita perché [System.IO.StreamReader] non contiene un metodo denominato 'nuovo'." – Gyromite

+0

Quale versione di. rete stai usando? Ho utilizzato il metodo di cui sopra per un paio di anni. – brendan62269

+0

Ho eseguito '[System.Environment] :: Version' in PowerShell, e il risultato è: Maggiore: 4, Minore: 0, Build : 30319, Revisione: 42000 – Gyromite

2

$ RespErr avrà i maggiori dettagli sulla BadRequest nel mio caso la sua

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

Sembra che funzioni solo in localhost, ho provato con il mio server attuale che non ha funzionato.

un altro modo per provare è questo

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