.Net HttpWebRequest.GetResponse () soulève exception lorsque le code d'état HTTP 400 (mauvaise demande) est renvoyée

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

  •  22-08-2019
  •  | 
  •  

Question

Je suis dans une situation où quand je reçois un code HTTP 400 du serveur, il est une façon tout à fait légale du serveur me disant ce qui était mal à ma demande (en utilisant un message dans le contenu de la réponse HTTP)

Cependant, le .NET HttpWebRequest déclenche une exception lorsque le code d'état est 400.

Comment puis-je gérer cela? Pour moi, un 400 est tout à fait légal, et plutôt utile. Le contenu HTTP a des informations importantes, mais l'exception me jette sur mon chemin.

Était-ce utile?

La solution

Ce serait bien s'il y avait un moyen d'éteindre « jeter le code non succès » mais si vous attrapez WebException vous pouvez au moins utiliser la réponse:

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

Vous pouvez vous résumer le « get me une réponse, même si ce n'est pas un code de succès » bit dans une méthode distincte. (Je vous suggère de jeter encore s'il n'y a pas une réponse, par exemple si vous ne pouviez pas vous connecter.)

Si la réponse d'erreur peut être importante (ce qui est rare), vous pouvez modifier HttpWebRequest.DefaultMaximumErrorResponseLength pour vous assurer d'obtenir toute l'erreur.

Autres conseils

Je sais que cela a déjà répondu il y a longtemps, mais je fait une méthode d'extension pour aider, espérons d'autres personnes qui viennent à cette question.

Code:

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

Utilisation:

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

Fait intéressant, le HttpWebResponse.GetResponseStream() que vous obtenez de la WebException.Response n'est pas le même que le flux de réponse que vous auriez reçu du serveur. Dans notre environnement, nous perdons des réponses du serveur réelles 400 état HTTP de code est de retour renvoyé au client en utilisant les objets HttpWebRequest/HttpWebResponse. D'après ce que nous avons vu, le flux de réponse associé au WebException's HttpWebResponse est généré au niveau du client et ne comprend pas du corps de réponse du serveur. Très frustrant, car nous voulons un message au client la raison de la mauvaise demande.

J'ai eu des problèmes similaires en essayant de se connecter au service OAuth2 de Google.

Je fini par écrire le POST manuellement, ne pas utiliser WebRequest, comme ceci:

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 réponse qui sont écrites sur le flux de réponse contient le texte d'erreur spécifique que vous êtes après.

En particulier, mon problème est que je mettais entre lignes de fond des morceaux de données codées URL. Quand je les ai sortis, tout fonctionnait. Vous pourriez être en mesure d'utiliser une technique similaire pour vous connecter à votre service et lisez le texte d'erreur de réponse réelle.

Essayez ceci (il est VB-Code: -):

Try

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

Une version asynchrone de fonction d'extension:

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

résolu pour moi:
https://gist.github.com/beccasaurus/929007/a8f820b153a1cfdee3d06a9c0a1d7ebfced8bb77

TL; DR:
Problème: localhost retourne le contenu prévu, IP à distance modifie 400 contenu à
« Bad Request » Solution: Ajout <httpErrors existingResponse="PassThrough"></httpErrors> à web.config/configuration/system.webServer résolu pour moi; maintenant tous les serveurs (locaux et distants) renvoient le même contenu (généré par moi) quelle que soit l'adresse IP et / ou le code HTTP je retourne.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top