HttpWebRequest.GetResponse在HTTP 304状态码下抛出WebException异常。

31

当 web 服务器用 HTTP 304(未修改)响应HttpWebRequest.GetResponse()时,GetResponse()会抛出WebException异常,这对我来说非常奇怪。这是设计如此还是我漏掉了什么明显的东西?

5个回答

49

好的,这似乎是一个设计行为,并且是一个完美的令人烦恼的异常的例子。可以通过以下方式解决:

public static HttpWebResponse GetHttpResponse(this HttpWebRequest request)
{
    try
    {
        return (HttpWebResponse) request.GetResponse();
    }
    catch (WebException ex)
    {
        if(ex.Response == null || ex.Status != WebExceptionStatus.ProtocolError)
            throw; 

        return (HttpWebResponse)ex.Response;
    }
}

3
大多数情况下这样做是可行的,但有些Web服务器在返回404错误时可能会返回响应正文。在这种情况下,上面的代码将把404视为对待304一样! - comshak
@comshak 这是一个“好知道”的事情。调用代码必须知道哪些响应码是可以接受的。 - roufamatic
1
我还添加了 || ((HttpWebResponse) ex.Response).StatusCode != HttpStatusCode.NotModified - Danny Beckett
你应该更新代码,使用C# 6.0的when语句! - binki
1
作为额外的奖励,以前可以使用[DebuggerNonUserCode]修饰方法,当抛出异常时,调试器不会停在该方法中。通过这种方式,可以包装和忽略设计不良的异常。但现在需要一个注册表设置 - crokusek

7

这真的是一个令人沮丧的问题,但可以通过使用以下扩展方法类并调用request.BetterGetResponse()来替代解决。

//-----------------------------------------------------------------------
//
//     Copyright (c) 2011 Garrett Serack. All rights reserved.
//
//
//     The software is licensed under the Apache 2.0 License (the "License")
//     You may not use the software except in compliance with the License.
//
//-----------------------------------------------------------------------

namespace CoApp.Toolkit.Extensions {
    using System;
    using System.Net;

    public static class WebRequestExtensions {
        public static WebResponse BetterEndGetResponse(this WebRequest request, IAsyncResult asyncResult) {
            try {
                return request.EndGetResponse(asyncResult);
            }
            catch (WebException wex) {
                if( wex.Response != null ) {
                    return wex.Response;
                }
                throw;
            }
        }

        public static WebResponse BetterGetResponse(this WebRequest request) {
            try {
                return request.GetResponse();
            }
            catch (WebException wex) {
                if( wex.Response != null ) {
                    return wex.Response;
                }
                throw;
            }
        }
    }
}

您可以在此处阅读有关此主题的博客文章。

博客文章涉及到it技术相关内容,并介绍了如何修复WebRequests的异常抛出问题,以便返回状态。请点击链接查看详情。


5
避免出现System.WebException的方法是将AllowAutoRedirect属性设置为false。这会禁用WebRequest的自动重定向逻辑。对于304重定向请求,它似乎存在问题,因为它不是严格意义上的真正重定向。当然,这也意味着其他重定向请求3xx必须手动处理。

1
绝对太棒了。如果我不需要笨重的异常机制,为什么要付费呢? - jsuddsjr

3

提醒一下,这是对Anton Gogolev的回答的更新,使用了C#6 (VS2015)的when子句。在使用调试器时,它会少一个捕获点,让人感觉不那么烦人:

public static HttpWebResponse GetHttpResponse(this HttpWebRequest request)
{
    try
    {
        return (HttpWebResponse) request.GetResponse();
    }
    catch (WebException ex)
        when (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
    {
        return (HttpWebResponse) ex.Response;
    }
}

0

我也遇到了这个代码问题:

try
{
    ...
    var webResponse = req.GetResponse();
    ...
}
catch (WebException ex)
{
    Log.Error("Unknown error occured", ex);
    //throw; 
}

看起来,如果远程服务器返回304状态码,必须通过抛出此错误或返回自定义的304状态码将其传递给浏览器,以便浏览器可以返回缓存的响应。否则,您可能会从远程服务器得到空的响应。

因此,在我的情况下,为了实现正常行为和正确的缓存处理,应该是这样的:

try
{
    ...
    var webResponse = req.GetResponse();
    ...
}
catch (WebException ex)
{
    if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotModified)
        throw;
    Log.Error("Unknown error occured", ex);
}

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