2016-03-29 6 views
8

Ho scritto un piccolo script PowerShell per inviare una richiesta a un server e ottenere un risultato XML semplice.Perché Invoke-WebRequest e Invoke-RestMethod non riescono e hanno esito positivo allo stesso tempo?

PowerShell Script

$xml = "<?xml version='1.0' encoding='utf-8'?><Search><ID>278A87E1-1BC2-4E19-82E9-8BBE31D67D20</ID></Search>" 
$response = Invoke-RestMethod -Method Post -Uri "http://localhost/search" -ContentType "application/xml" -Body $xml 

Questo è tutto, davvero semplice e non c'è ragione che posso vedere per essere fallendo. Ho anche provato la sceneggiatura con Invoke-WebRequest ed entrambi falliscono. L'errore restituito è Invoke-RestMethod : Value cannot be null. Parameter name: name. La cosa strana è che quando lo monitoro con Wireshark, vedo la connessione, vedo il POST e vedo il risultato dal server e tutto sembra perfetto ma il cmdlet sta dicendo che non è riuscito (e sì, il codice di ritorno è 200).

Se eseguo il Invoke-WebRequest/Invoke-RestMethod con il parametro -OutFile, esso funziona correttamente senza errori e salva il risultato nel file specificato; -OutVariable fallisce nel caso ve lo stiate chiedendo.

Il risultato è un file xml, le intestazioni specificano che è xml e che l'xml è formattato correttamente.

Risultato quando ha successo

<?xml version="1.0" encoding="UTF-8" ?> 
<Result version="1.0" xmlns="urn:xmlns-org"> 
    <searchID>{278a87e1-1bc2-4e19-82e9-8bbe31d67d20}</searchID> 
    <responseStatus>true</responseStatus> 
    <responseStatusStrg>MORE</responseStatusStrg> 
    <numOfMatches>40</numOfMatches> 
</Result> 

Qualcuno sa il motivo per cui i Invoke-XXX cmdlet stanno tornando un errore e che cosa posso fare per risolvere il problema? Ancora una volta, funziona perfettamente bene quando utilizzo il parametro -OutFile e anche quando non riesce riesco a vedere una conversazione corretta tra lo script e il server in Wireshark.

Inoltre, se uso -Verbose mi dice il seguente:

VERBOSE: POST http://localhost/search with -1-byte payload 
VERBOSE: received X-byte response of content type application/xml; charset="UTF-8" 

Dove X-byte è la dimensione effettiva della risposta, ma, ovviamente, si differenzia con ogni risposta a seconda dei dati inviati al server. Mi sembra strano che il cmdlet non funzioni ma dice che ha ricevuto una risposta con i dati e che ha inviato un payload -1-byte.

risposta

7

Sono andato avanti e ho esaminato il codice del cmdlet Invoke-WebRequest e ho scoperto perché non funziona con questo particolare errore.

È in corso una chiamata su System.Globalization.EncodingTable.GetCodePageFromName. La codifica viene passata a tale funzione come parametro e la codifica viene recuperata dal cmdlet tramite l'intestazione Content-Type. Nel caso di questo server il Content-Type è stato rinviato nella risposta come Content-Type: application/xml; charset="UTF-8".

Il problema con questo è che le virgolette non sono standard per avvolgere il valore in charset in modo che il cmdlet lo analizzi come "UTF-8" anziché UTF-8 valido. Il cmdlet passa "UTF-8" alla funzione e la funzione genera un'eccezione che indica che la codifica fornita non è valida. Questo va bene e avrebbe molto più senso se questo è ciò che è stato segnalato nell'eccezione finale, ma non lo è.

L'eccezione codifica non valido viene catturato dalla funzione Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault e nel gestore eccezioni che chiama GetEncoding nuovo, ma con un parametro nullo che si traduce in finale ArgumentNullException parametro name.

Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault

internal static Encoding GetEncodingOrDefault(string characterSet) 
{ 
    string name = string.IsNullOrEmpty(characterSet) ? "ISO-8859-1" : characterSet; 
    try 
    { 
    return Encoding.GetEncoding(name); 
    } 
    catch (ArgumentException ex) 
    { 
    return Encoding.GetEncoding((string) null); 
    } 
} 

La chiamata al GetEncoding all'interno della istruzione catch fa scattare il seguente codice all'interno GetCodePageFromName che è a sua volta chiamato da GetEncoding

if (name==null) { 
    throw new ArgumentNullException("name"); 
} 

PowerShell sta gestendo questo correttamente dal momento che tecnicamente è un valore non valido, ma si potrebbe pensare che chiamerebbero Trim("\"") solo per sicurezza.

+0

Sto riscontrando questo problema con 'SimpleHTTerver' di Python 2.7. – Kupiakos

+0

Grazie per aver scoperto la causa principale. Ho visto questo manifest su un Windows Server 2012 R2 completamente rattoppato con PowerShell (WMF) 5.1 installato. Prendere lo stesso codice su Windows 10 o Windows Server 2016 e non ci sono problemi. Molto deludente in quanto non sembra esserci una soluzione. – Lewis