检查HttpStatusCode是否表示成功或失败

132

假设我有以下变量:

System.Net.HttpStatusCode status = System.Net.HttpStatusCode.OK;

我该如何检查这是一个成功状态码还是失败状态码?

例如,我可以执行以下操作:

int code = (int)status;
if(code >= 200 && code < 300) {
    //Success
}

我也可以有某种白名单:

HttpStatusCode[] successStatus = new HttpStatusCode[] {
     HttpStatusCode.OK,
     HttpStatusCode.Created,
     HttpStatusCode.Accepted,
     HttpStatusCode.NonAuthoritativeInformation,
     HttpStatusCode.NoContent,
     HttpStatusCode.ResetContent,
     HttpStatusCode.PartialContent
};
if(successStatus.Contains(status)) //LINQ
{
    //Success
}

这些方案都没能说服我,我希望有一个 .NET 类或方法可以代替我完成这项工作,例如:

bool isSuccess = HttpUtilities.IsSuccess(status);

你需要执行 int code = (int)Response.StatusCode,然后你需要创建自己的 Enum。这里有一个有效的示例,请参考 https://dev59.com/oHM_5IYBdhLWcg3wjj0p - MethodMan
你是否使用了 HttpClient 类? - dcastro
1
@dcastro 不好意思,我正在使用一个高级API,它可能(也可能不)在内部使用它。该API公开响应的状态代码,但不会公开内部的HttpResponseMessage,例如。 - Matias Cicero
1
@MatiCicero 真遗憾 :/ 你可以始终重用 HttpResponseMessage.IsSuccessStatusCode 的实现(请参见我的答案),它与您的第一种方法完全相同,并将其作为 HttpStatusCode 类型的扩展方法。 - dcastro
7个回答

245

如果您正在使用HttpClient类,则会返回一个HttpResponseMessage

此类具有一个称为IsSuccessStatusCode的有用属性,它可以为您执行检查。

using (var client = new HttpClient())
{
    var response = await client.PostAsync(uri, content);
    if (response.IsSuccessStatusCode)
    {
        //...
    }
}

如果你感到好奇,这个属性是这样实现的:implemented

public bool IsSuccessStatusCode
{
    get { return ((int)statusCode >= 200) && ((int)statusCode <= 299); }
}

如果您不直接使用HttpClient,那么您可以重复使用此算法。

您还可以使用EnsureSuccessStatusCode来在响应失败时抛出异常。


3
FYI:对我来说是'response.IsSuccessful'。 - Topher Birth
你的回答非常有帮助,但现在它的工作方式是这样的:if (response.IsCompletedSuccessfully) { // } - Saima

21

接受的答案让我有点不爽,因为它在第二部分包含了魔法数字(虽然它们是标准的)。而第一部分对于普通整数状态码并不通用,虽然它接近于我的答案。

您可以通过实例化HttpResponseMessage并检查成功来完全实现相同的结果,如果值小于零或大于999,则会抛出参数异常。

if (new HttpResponseMessage((HttpStatusCode)statusCode).IsSuccessStatusCode)
{
    // ...
}

这并不是非常简明,但您可以将其制作成一个扩展程序。


1
这对我非常有效,因为我只有一个HttpStatusCode而没有Response消息。干得好! - Todd Vance
11
“被接受的答案让我有点不舒服,因为它包含了魔数(尽管它们是标准的)。如果它们是标准化的、被理解并且永远不会改变,那么它们就不是“魔数”了。直接使用这些代码没有任何问题。如果你有‘IsSuccessStatusCode’,那就好好用它(就像被接受的答案说的那样)。否则,除非你要在很多地方执行此检查,否则不要通过使用抽象层添加自己的杂物。” - Ed S.
7
请注意,实例化 HttpResponseMessage 并使用其属性所需的时间比使用 int 检查两个逻辑条件更长。 - Miro J.

18

我偏爱于扩展方法的可发现性。

public static class HttpStatusCodeExtensions
{
    public static bool IsSuccessStatusCode(this HttpStatusCode statusCode)
    {
        var asInt = (int)statusCode;
        return asInt >= 200 && asInt <= 299;
    }
}
只要您的命名空间在作用域内,使用方法就是 statusCode.IsSuccessStatusCode()

扩展方法很酷,但我有点困惑——这不是与HTTPClient或IHTTPClientFactory一起使用的HTTPResponseMessage的IsSuccessStatusCode属性做的相同的事情吗?@DCastro甚至向我们展示了在.NET中它是如何实现的。那么,在2xx范围内的HTTP状态码方面,我什么时候/为什么要使用这样的扩展方法呢? - sfors says reinstate Monica
5
@sfors,是的,但如果您只有一个HttpStatusCode怎么办?有很多库不会使用或显示HttpResponseMessage,但会向您提供状态代码。 - bojingo
@bojingo 我还是不明白为什么需要扩展方法:如果库只返回状态码(比如404),那就直接用httpResponse = new HttpResponseMessage((HttpStatusCode)404);然后继续进行下一步。 - undefined

13

HttpResponseMessage类有一个IsSuccessStatusCode属性,在查看源代码时,它就像这样。正如usr已经建议的那样,200-299可能是你能做到的最好。

public bool IsSuccessStatusCode
{
    get { return ((int)statusCode >= 200) && ((int)statusCode <= 299); }
}

12

在@TomDoesCode的回答基础上,如果您正在使用HttpWebResponse,您可以添加此扩展方法:

public static bool IsSuccessStatusCode(this HttpWebResponse httpWebResponse)
{
    return ((int)httpWebResponse.StatusCode >= 200) && ((int)httpWebResponse.StatusCode <= 299);
}

4

这取决于您调用的HTTP资源。通常,2xx范围被定义为成功状态码的范围。但并非每个HTTP服务器都遵循这一约定。

例如,在网站上提交表单通常会返回302重定向。

如果您想设计一个通用方法,那么code >= 200 && code < 300的思路可能是您最好的选择。

如果您正在调用自己的服务器,则应确保将标准化为 200


2
这是对之前答案的扩展,避免了为每次调用创建和随后垃圾回收新对象的过程。
public static class StatusCodeExtensions
{
    private static readonly ConcurrentDictionary<HttpStatusCode, bool> IsSuccessStatusCode = new ConcurrentDictionary<HttpStatusCode, bool>();
    public static bool IsSuccess(this HttpStatusCode statusCode) => IsSuccessStatusCode.GetOrAdd(statusCode, c => new HttpResponseMessage(c).IsSuccessStatusCode);
}

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