.Net HttpWebRequest.GetResponse () solleva un'eccezione quando viene restituito il codice di stato HTTP 400 (Richiesta non valida)

StackOverflow https://stackoverflow.com/questions/692342

  •  22-08-2019
  •  | 
  •  

Domanda

Sono in una situazione in cui, quando ottengo un HTTP 400 del codice dal server, è un modo completamente legale del server di dirmi che cosa era sbagliato con la mia richiesta (usando un messaggio nel contenuto della risposta HTTP)

Tuttavia, il NET HttpWebRequest solleva un'eccezione quando il codice di stato è 400.

Come faccio a gestire questa situazione? Per me un 400 è completamente legale, e piuttosto disponibile. Il contenuto HTTP ha alcune informazioni importanti, ma l'eccezione mi butta fuori il mio percorso.

È stato utile?

Soluzione

Sarebbe bello se ci fosse un modo di spegnere "buttare sul codice non-successo", ma se si cattura WebException si può almeno usare la risposta:

using System;
using System.IO;
using System.Web;
using System.Net;

public class Test
{
    static void Main()
    {
        WebRequest request = WebRequest.Create("http://csharpindepth.com/asd");
        try
        {
            using (WebResponse response = request.GetResponse())
            {
                Console.WriteLine("Won't get here");
            }
        }
        catch (WebException e)
        {
            using (WebResponse response = e.Response)
            {
                HttpWebResponse httpResponse = (HttpWebResponse) response;
                Console.WriteLine("Error code: {0}", httpResponse.StatusCode);
                using (Stream data = response.GetResponseStream())
                using (var reader = new StreamReader(data))
                {
                    string text = reader.ReadToEnd();
                    Console.WriteLine(text);
                }
            }
        }
    }
}

Come si potrebbe incapsulare il "get me una risposta, anche se non è un codice di successo" bit in un metodo separato. (Io suggerirei ancora buttare, se non v'è una risposta, ad esempio se non è possibile collegare.)

Se la risposta di errore può essere grande (che è insolito) si può decidere di modificare HttpWebRequest.DefaultMaximumErrorResponseLength per essere sicuri di ottenere l'intera errore.

Altri suggerimenti

So che questo è già stato risposto molto tempo fa, ma ho fatto un metodo di estensione per aiutare spera altre persone che vengono a questa domanda.

Codice:

public static class WebRequestExtensions
{
    public static WebResponse GetResponseWithoutException(this WebRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        try
        {
            return request.GetResponse();
        }
        catch (WebException e)
        {
            if (e.Response == null)
            {
                throw;
            }

            return e.Response;
        }
    }
}

Utilizzo:

var request = (HttpWebRequest)WebRequest.CreateHttp("http://invalidurl.com");

//... (initialize more fields)

using (var response = (HttpWebResponse)request.GetResponseWithoutException())
{
    Console.WriteLine("I got Http Status Code: {0}", response.StatusCode);
}

È interessante notare che il HttpWebResponse.GetResponseStream() che si ottiene dalla WebException.Response non è la stessa come il flusso di risposta che avrebbe ricevuto dal server. Nel nostro ambiente, stiamo perdendo le risposte del server effettivi quando un 400 di stato HTTP il codice viene restituito al client utilizzando gli oggetti HttpWebRequest/HttpWebResponse. Da quello che abbiamo visto, il flusso di risposta associata al WebException's HttpWebResponse viene generato sul client e non include alcuna del corpo risposta dal server. Molto frustrante, perché vogliamo un messaggio al client il motivo per il cattivo richiesta.

Ho avuto problemi simili quando si cerca di connettersi al servizio OAuth2 di Google.

ho finito per scrivere il POST manualmente, non usare WebRequest, in questo modo:

TcpClient client = new TcpClient("accounts.google.com", 443);
Stream netStream = client.GetStream();
SslStream sslStream = new SslStream(netStream);
sslStream.AuthenticateAsClient("accounts.google.com");

{
    byte[] contentAsBytes = Encoding.ASCII.GetBytes(content.ToString());

    StringBuilder msg = new StringBuilder();
    msg.AppendLine("POST /o/oauth2/token HTTP/1.1");
    msg.AppendLine("Host: accounts.google.com");
    msg.AppendLine("Content-Type: application/x-www-form-urlencoded");
    msg.AppendLine("Content-Length: " + contentAsBytes.Length.ToString());
    msg.AppendLine("");
    Debug.WriteLine("Request");
    Debug.WriteLine(msg.ToString());
    Debug.WriteLine(content.ToString());

    byte[] headerAsBytes = Encoding.ASCII.GetBytes(msg.ToString());
    sslStream.Write(headerAsBytes);
    sslStream.Write(contentAsBytes);
}

Debug.WriteLine("Response");

StreamReader reader = new StreamReader(sslStream);
while (true)
{  // Print the response line by line to the debug stream for inspection.
    string line = reader.ReadLine();
    if (line == null) break;
    Debug.WriteLine(line);
}

La risposta che viene scritto nel flusso di risposta contiene il testo di errore specifico che stai cercando.

In particolare, il mio problema era che stavo mettendo linee di fondo tra i pezzi di dati con codifica URL. Quando li ho tirato fuori, tutto ha funzionato. Potreste essere in grado di utilizzare una tecnica simile a connettersi al servizio e leggere il testo di errore risposta effettiva.

Prova questo (è VB-Code: -):

Try

Catch exp As WebException
  Dim sResponse As String = New StreamReader(exp.Response.GetResponseStream()).ReadToEnd
End Try

Una versione asincrona di funzione di estensione:

    public static async Task<WebResponse> GetResponseAsyncNoEx(this WebRequest request)
    {
        try
        {
            return await request.GetResponseAsync();
        }
        catch(WebException ex)
        {
            return ex.Response;
        }
    }

Ciò ha risolto per me:
https://gist.github.com/beccasaurus/929007/a8f820b153a1cfdee3d06a9c0a1d7ebfced8bb77

TL; DR:
Problema:
localhost rendimenti del contenuto previsto, IP remoto altera 400 contenuti
"Bad Request" Soluzione:
L'aggiunta di <httpErrors existingResponse="PassThrough"></httpErrors> a web.config/configuration/system.webServer risolto questo per me; ora tutti i server (locali e remoti) restituiscono lo stesso esatto contenuto (generato da me) indipendentemente l'indirizzo IP e / o il codice HTTP al mio ritorno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top