.net - example - webrequest get data
.Net HttpWebRequest.GetResponse() provoca una excepción cuando se devuelve el código de estado HTTP 400(solicitud incorrecta) (6)
Estoy en una situación en la que cuando obtengo un código HTTP 400 del servidor, es una forma completamente legal de que el servidor me diga cuál fue el problema con mi solicitud (usando un mensaje en el contenido de respuesta HTTP)
Sin embargo, .NET HttpWebRequest genera una excepción cuando el código de estado es 400.
¿Cómo manejo esto? Para mí, un 400 es completamente legal y bastante útil. El contenido HTTP tiene información importante, pero la excepción me saca de mi camino.
Curiosamente, el HttpWebResponse.GetResponseStream()
que obtienes de WebException.Response
no es lo mismo que el flujo de respuesta que recibirías del servidor. En nuestro entorno, estamos perdiendo respuestas reales del servidor cuando se devuelve un código de estado 400 HTTP al cliente utilizando los objetos HttpWebRequest/HttpWebResponse
. Según lo que hemos visto, el flujo de respuesta asociado con WebException''s HttpWebResponse
se genera en el cliente y no incluye el cuerpo de la respuesta del servidor. Muy frustrante, ya que queremos devolverle al cliente el motivo de la mala solicitud.
Prueba esto (es VB-Code :-):
Catch exp As WebException
''Read the real response from the server
Dim sResponse As String = New StreamReader(exp.Response.GetResponseStream()).ReadToEnd
Sé que esto ya se ha respondido hace mucho tiempo, pero hice un método de extensión para ayudar a otras personas que llegan a esta pregunta.
Código:
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;
}
}
}
Uso:
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);
}
Sería bueno si hubiera alguna forma de desactivar el "código de lanzamiento sin éxito", pero si capturas WebException puedes al menos usar la respuesta:
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);
}
}
}
}
}
Es posible que desee encapsular el bit "obtener una respuesta incluso si no es un código de éxito" en un método diferente. (Sugeriría que aún arrojes si no hay una respuesta, por ejemplo, si no pudiste conectarte).
Si la respuesta de error puede ser grande (lo cual es inusual) es posible que desee ajustar HttpWebRequest.DefaultMaximumErrorResponseLength
para asegurarse de que obtiene el error completo.
Tuve problemas similares al intentar conectarme al servicio OAuth2 de Google.
Terminé escribiendo el POST manualmente, no usando WebRequest, así:
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 respuesta que se escribe en la secuencia de respuesta contiene el texto de error específico que está buscando.
En particular, mi problema era que estaba colocando líneas finales entre piezas de datos codificadas en URL. Cuando los saqué, todo funcionó. Es posible que pueda utilizar una técnica similar para conectarse a su servicio y leer el texto de error de respuesta real.
Una versión asincrónica de la función de extensión:
public static async Task<WebResponse> GetResponseAsyncNoEx(this WebRequest request)
{
try
{
return await request.GetResponseAsync();
}
catch(WebException ex)
{
return ex.Response;
}
}