当HttpWebRequest.GetResponse()失败时如何获取错误信息

103
我正在发起一个HttpWebRequest请求并获取响应。偶尔会收到500(或至少是5##)错误,但没有说明。我可以控制两个端点,并希望接收端获得更多信息。例如,我想将服务器的异常消息从服务器传递到客户端。使用HttpWebRequest和HttpWebResponse是否可能实现此目的?
代码:
try
{
    HttpWebRequest webRequest = HttpWebRequest.Create(URL) as HttpWebRequest;
    webRequest.Method = WebRequestMethods.Http.Get;
    webRequest.Credentials = new NetworkCredential(Username, Password);
    webRequest.ContentType = "application/x-www-form-urlencoded";
    using(HttpWebResponse response = webRequest.GetResponse() as HttpWebResponse)
    {
        if(response.StatusCode == HttpStatusCode.OK)
        {
            // Do stuff with response.GetResponseStream();
        }
    }
}
catch(Exception ex)
{
    ShowError(ex);
    // if the server returns a 500 error than the webRequest.GetResponse() method
    // throws an exception and all I get is "The remote server returned an error: (500)."
}
任何关于这个的帮助都将不胜感激。

我只想补充一下,通常建议尽量减少try语句包装的内容。在你的情况下,直到using语句之前的所有内容都可以写在外面。 - SSHunter49
6个回答

183

使用 HttpWebRequest 和 HttpWebResponse 能实现这个吗?

您可以让您的 Web 服务器捕获并将异常文本写入响应正文,然后将状态代码设置为 500。现在,当客户端遇到 500 错误时,它会抛出异常,但您可以读取响应流并获取异常消息。

因此,您可以捕获 WebException,如果从服务器返回非 200 状态代码,则会抛出该异常,并读取其正文:

catch (WebException ex)
{
    using (var stream = ex.Response.GetResponseStream())
    using (var reader = new StreamReader(stream))
    {
        Console.WriteLine(reader.ReadToEnd());
    }
}
catch (Exception ex)
{
    // Something more serious happened
    // like for example you don't have network access
    // we cannot talk about a server exception here as
    // the server probably was never reached
}

谢谢!需要注意的是,在 using 语句内部的流将不会在 using 语句外部可用,因为 WebResponse 的处理器将清除它。这让我困惑了几分钟。 - Thorin
@Thorin。第一条语句中的“stream”将继续传递到下一条语句。就像单行IF语句一样,例如if(something)do-stuff-here; - RealityDysfunction
3
GetRequestStreamGetResponse 可能会抛出异常? - PreguntonCojoneroCabrón
@PreguntonCojoneroCabrón 是的,看起来不太对劲。幸运的是,微软引入了 HttpClient 类,我认为大多数人现在都在使用它。https://msdn.microsoft.com/zh-cn/library/system.net.http.httpclient(v=vs.118).aspx - Morten Nørgaard
WebException只有在Status==WebExceptionStatus.ProtocolError时才会填充Response。大多数错误都不允许您从服务器访问响应主体,因此Response将为空。 - Suncat2000

11

当我尝试检查FTP网站上是否存在某个文件时,遇到了这个问题。如果文件不存在,那么在尝试检查其时间戳时会出现错误。但是我想通过检查类型来确保错误不是其他原因导致的。

WebExceptionResponse属性将是FtpWebResponse类型的,您可以检查它的StatusCode属性以查看哪种FTP错误

以下是我最终使用的代码:

    public static bool FileExists(string host, string username, string password, string filename)
    {
        // create FTP request
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + host + "/" + filename);
        request.Credentials = new NetworkCredential(username, password);

        // we want to get date stamp - to see if the file exists
        request.Method = WebRequestMethods.Ftp.GetDateTimestamp;

        try
        {
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            var lastModified = response.LastModified;

            // if we get the last modified date then the file exists
            return true;
        }
        catch (WebException ex)
        {
            var ftpResponse = (FtpWebResponse)ex.Response;

            // if the status code is 'file unavailable' then the file doesn't exist
            // may be different depending upon FTP server software
            if (ftpResponse.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
            {
                return false;
            }

            // some other error - like maybe internet is down
            throw;
        }
    }

6

我遇到了类似的情况:

我正在尝试在消耗SOAP服务时使用BasicHTTPBinding来读取HTTP错误时的原始响应。

然而,当使用GetResponseStream()读取响应时,出现以下错误:

流不可读

因此,这段代码适用于我:

try
{
    response = basicHTTPBindingClient.CallOperation(request);
}
catch (ProtocolException exception)
{
    var webException = exception.InnerException as WebException;
    var rawResponse = string.Empty;

    var alreadyClosedStream = webException.Response.GetResponseStream() as MemoryStream;
    using (var brandNewStream = new MemoryStream(alreadyClosedStream.ToArray()))
    using (var reader = new StreamReader(brandNewStream))
        rawResponse = reader.ReadToEnd();
}

1
你还可以使用这个库,它将HttpWebRequest和Response封装成简单的方法,根据结果返回对象。 它使用了一些在这些答案中描述的技术,并且有大量受到这个和类似线程答案启发的代码。 它自动捕获任何异常,试图抽象出尽可能多的样板代码以使这些网络请求尽可能简单,并自动反序列化响应对象。
使用此包装器编写代码的示例非常简单,如下所示:
    var response = httpClient.Get<SomeResponseObject>(request);
    
    if(response.StatusCode == HttpStatusCode.OK)
    {
        //do something with the response
        console.Writeline(response.Body.Id); //where the body param matches the object you pass in as an anonymous type.  
    }else {
         //do something with the error
         console.Writelint(string.Format("{0}: {1}", response.StatusCode.ToString(), response.ErrorMessage);

    }

完全披露 这个库是一个免费的开源包装库,我是该库的作者。我没有从中获得任何收益,但多年来发现它非常有用,相信仍在使用HttpWebRequest/HttpWebResponse类的任何人也会觉得如此。

它不是万能药,但支持get、post、delete以及get和post的异步和非异步方式,同时支持JSON或XML请求和响应。截至2020年6月21日,它正在积极维护。


0

有时ex.Response也会引发NullReferenceException,因此以下是最佳处理方法

catch (WebException ex)
{
    using (var stream = ex?.Response?.GetResponseStream())
    if(stream != null)
    using (var reader = new StreamReader(stream))
    {
        Console.WriteLine(reader.ReadToEnd());
    }
    // todo...
}
catch (Exception ex)
{
    // todo...
}

-5
**Answer Updated on 14-03-2022**
HttpWebRequest myHttprequest = null;
HttpWebResponse myHttpresponse = null;
try
{
myHttpRequest = (HttpWebRequest)WebRequest.Create(URL);
myHttpRequest.Method = "POST";
myHttpRequest.ContentType = "application/x-www-form-urlencoded";
myHttpRequest.ContentLength = urinfo.Length;
StreamWriter writer = new StreamWriter(myHttprequest.GetRequestStream());
writer.Write(urinfo);
writer.Close();
myHttpresponse = (HttpWebResponse)myHttpRequest.GetResponse();
if (myHttpresponse.StatusCode == HttpStatusCode.OK)
 {
   //Success code flow
 }
myHttpresponse.Close(); 
}
catch(WebException e) {
    Console.WriteLine("This program is expected to throw WebException on successful run."+
                    "\n\nException Message :" + e.Message);
    if(e.Status == WebExceptionStatus.ProtocolError) {
        Console.WriteLine("Status Code : {0}", 
    ((HttpWebResponse)e.Response).StatusCode);
    Console.WriteLine("Status Description : {0}", 
    ((HttpWebResponse)e.Response).StatusDescription);
}
**Updated Answer with try catch block**
[docs.microsoft][1]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接