212 votes

.Net HttpWebRequest.GetResponse() lève une exception lorsque le code d'état http 400 (mauvaise requête) est renvoyé.

Je me trouve dans une situation où, lorsque je reçois un code HTTP 400 du serveur, il s'agit d'un moyen tout à fait légal pour le serveur de me dire ce qui n'allait pas avec ma demande (en utilisant un message dans le contenu de la réponse HTTP).

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

Comment dois-je procéder ? Pour moi, un 400 est tout à fait légal et plutôt utile. Le contenu HTTP contient des informations importantes, mais l'exception me fait dévier de ma route.

6 votes

J'ai vécu la même chose. J'ai soumis une suggestion à l'équipe .NET Framework. N'hésitez pas à voter pour elle : connect.microsoft.com/VisualStudio/feedback/details/575075/

368voto

Jon Skeet Points 692016

Ce serait bien s'il y avait un moyen de désactiver la fonction "throw on non-success code", mais si vous attrapez une 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 pourriez encapsuler la partie "obtenir une réponse même si ce n'est pas un code de réussite" dans une méthode séparée. (Je vous suggère de continuer à lancer la méthode si vous n'obtenez pas de réponse, par exemple si vous n'avez pas pu vous connecter).

Si la réponse à l'erreur est importante (ce qui est inhabituel), vous pouvez modifier les paramètres suivants HttpWebRequest.DefaultMaximumErrorResponseLength pour être sûr d'obtenir l'intégralité de l'erreur.

6 votes

Le contenu du flux renvoyé par GetResponseStream() sur la réponse attachée à l'exception Web est simplement le nom du code d'état (par exemple "Bad Request") plutôt que la réponse réellement renvoyée par le serveur. Existe-t-il un moyen d'obtenir cette information ?

0 votes

@MarkWatts : Il devrait est ce qui a été renvoyé par le serveur, et ce dans toutes les situations que j'ai vues. Pouvez-vous reproduire ce phénomène avec une URL externe particulière ? Je vous suggère de poser une nouvelle question (en faisant référence à celle-ci) et de montrer ce qui se passe.

0 votes

Il s'avère qu'il ne le fait que lorsque la longueur du contenu de la réponse est nulle ; il ajoute une description textuelle du code d'état HTTP - 400 est simplement "Mauvaise demande", mais certains des autres sont plus descriptifs.

49voto

Matthew Points 10499

Je sais que la réponse à cette question a déjà été donnée il y a longtemps, mais j'ai créé une méthode d'extension pour aider les autres personnes qui se posent 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);
}

2 votes

WebException.Response peut et peut être null . Si c'est le cas, vous devez relancer la procédure.

0 votes

@DavidP Je suis d'accord, l'utilisation est un peu bizarre, mais pour la plupart des choses, vous devriez probablement utiliser HttpClient Au contraire, il est beaucoup plus configurable, et je pense que c'est la voie de l'avenir.

0 votes

Est-il vraiment nécessaire de vérifier si request == null ? Puisqu'il s'agit d'une méthode d'extension, essayer de l'utiliser sur un objet null devrait lever une exception de référence nulle avant d'atteindre la méthode d'extension code......, n'est-ce pas ?

14voto

Il est intéressant de noter que la HttpWebResponse.GetResponseStream() que vous obtenez de l WebException.Response n'est pas le même que le flux de réponses que vous auriez reçu du serveur. Dans notre environnement, nous perdons les réponses réelles du serveur lorsqu'un fichier 400 Statut HTTP est renvoyé au client à l'aide du code HttpWebRequest/HttpWebResponse objets. D'après ce que nous avons vu, le flux de réponses associé à l'objet WebException's HttpWebResponse est généré par le client et n'inclut pas le corps de la réponse du serveur. C'est très frustrant, car nous voulons indiquer au client la raison de la mauvaise requête.

0 votes

J'utilise la méthode HEAD et cela provoque cette exception, mais lorsque j'utilise GET, il n'y a pas de problème. Quel est le problème avec la méthode HEAD exactement ?

13voto

Jugglist Points 81

J'ai rencontré des problèmes similaires en essayant de me connecter au service OAuth2 de Google.

J'ai fini par écrire le POST manuellement, sans 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 est écrite dans le flux de réponse contient le texte d'erreur spécifique que vous recherchez.

En particulier, mon problème était que je mettais des lignes de fin entre des données codées en url. Lorsque je les ai enlevées, tout a fonctionné. Vous pourriez utiliser une technique similaire pour vous connecter à votre service et lire le texte d'erreur de la réponse.

2 votes

HttpWebRequest est tellement perturbé. Même les sockets sont plus faciles (parce qu'ils ne cachent pas les erreurs).

6voto

Bernd Points 11

Essayez ceci (c'est du code VB :-) :

Try

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X