• ASP.NET MVC + RESTful服务之HttpStatusResult


    开篇语与本主题无关,我非常尊敬的一个导师好几天没有见到人,今天听说原来是病了,人也出现了。在此祝愿他身体康健,长命百岁!

    使用ASP.NET MVC构建RESTful服务时,想到一个问题:在使用POST,PUT,DELETE方法发送请求时服务器端如何回传响应?如果在操作过程中发生了异常情况,如何通知客户端?

    带着这个问题,尝试着构建了一个ActionResult的派生类:

    namespace System.Web.Mvc
    {
        public class HttpStatusResult : ActionResult
        {
            public HttpStatusResult()
                : this(HttpStatusCode.OK)
            {
            }
    
            public HttpStatusResult(HttpStatusCode statusCode)
                : this(statusCode, "")
            {
            }
    
            public HttpStatusResult(HttpStatusCode statusCode, string content)
            {
                this.StatusCode = statusCode;
                this.Content = content;
            }
    
            public string Content { get; set; }
            public HttpStatusCode StatusCode { get; set; }
    
            public override void ExecuteResult(ControllerContext context)
            {
                context.HttpContext.Response.StatusCode = (int)StatusCode;
                context.HttpContext.Response.ContentType = "text/xml, charset=\"utf-8\"";
    
                if (string.IsNullOrEmpty(context.HttpContext.Request.Headers["Accept-Encoding"]) == false)
                {
                    string acceptEncoding = context.HttpContext.Request.Headers["Accept-Encoding"].ToLower();
    
                    if (acceptEncoding.Contains("gzip"))
                    {
                        context.HttpContext.Response.Filter = new GZipStream(context.HttpContext.Response.Filter, CompressionMode.Compress);
                        context.HttpContext.Response.AppendHeader("Content-Encoding", "gzip");
                    }
                }
    
                using (var writer = XmlWriter.Create(context.HttpContext.Response.Output))
                {
                    this.ResponseContent.WriteTo(writer);
                }
            }
    
            private XmlDocument ResponseContent
            {
                get
                {
                    XmlDocument xml = new XmlDocument();
                    xml.LoadXml(string.Format("<?xml version=\"1.0\"?><response xmlns=\"http://schema.cleversoft.com/webutil/httpstatusresult/1.0/\"><content>{0}</content></response>", this.Content));
                    return xml;
                }
            }
        }
    }
    

    使用这个类,可以向请求的客户端返回一个Http Status信息,如果操作正常,则视情况使用200,202,204。情况是什么?据HTTP/1.1定义:

    POST:

    The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.

    If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header.

    PUT:

    If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response. If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate successful completion of the request.

    DELETE:

    A successful response SHOULD be 200 (OK) if the response includes an entity describing the status, 202 (Accepted) if the action has not yet been enacted, or 204 (No Content) if the action has been enacted but the response does not include an entity.

    总而言之,看你真正做了什么操作,返回一个与之匹配的HTTP Status Code。在此过程中也有可能遇到需要使用3XX系统的情况,不过我要做的服务中还没有这么复杂的规划,据以前的学习发现,发现Google的服务中3XX用的比较多,整的比较复杂。

    上面这些只仅仅是发送POST,PUT,DELETE成功的响应,如果仅是为了这个原因,似乎就没有必要去做HttpStatusResult类型了。自已去实现RESTful服务,异常处理肯定是必须要考虑的内容。在我现在的设想中,如果一些操作发生了服务器端的错误,那就得使用HttpStatusResult类型来向客户端传递错误信息,即HttpStatusResult.Content属性。使用方法如下:

      return new HttpStatusResult(System.Net.HttpStatusCode.InternalServerError, "Exception Message.");  
    

    在发送异常时我使用了InternalServerError(500)。

    问题来了,使用了500以后,客户端并不知道这是你“处心积虑”的发出来了,它只知道服务器端出错了,然后在WebRequest.GetResponse()时直接抛出异常了,而且没有返回WebResponse,那我们使用Content返回的异常信息岂不成了笑话了?所幸,M$也没有这么笨,大家可以仔细看下WebException的定义就会发现,原来使用WebException.Response就可以获得刚才服务器返回的响应,当然这时WebException.Status的状态必须不能为ConnectFailure(值为2),这个Response属性也必须不能为空(废话),接下来,你就使用XmlReader从ResponseStream中拿数据吧,数据结构的定义可以视个人喜好定义:)。这里比较推荐的方法是在响应的xml中定义一个NameSpace,为什么nia?因为这样你就可以确定这是你自已,而不是他人发来的响应。

    最后,转一下Http Status Code定义:

    100 Continue

    101 Switching Protocols

    102 Processing

    200 OK

    201 Created

    202 Accepted

    203 Non-Authoritative Information

    204 No Content

    205 Reset Content

    206 Partial Content

    207 Multi-Status

    226 IM Used

    300 Multiple Choices

    301 Moved Permanently

    302 Found

    303 See Other

    304 Not Modified

    305 Use Proxy

    306 (Unused)

    307 Temporary Redirect

    400 Bad Request

    401 Unauthorized

    402 Payment Required

    403 Forbidden

    404 Not Found

    405 Method Not Allowed

    406 Not Acceptable

    407 Proxy Authentication Required

    408 Request Timeout

    409 Conflict

    410 Gone

    411 Length Required

    412 Precondition Failed

    413 Request Entity Too Large

    414 Request-URI Too Long

    415 Unsupported Media Type

    416 Requested Range Not Satisfiable

    417 Expectation Failed

    418 I'm a teapot

    422 Unprocessable Entity

    423 Locked

    424 Failed Dependency

    425 (Unordered Collection)

    426 Upgrade Required

    500 Internal Server Error

    501 Not Implemented

    502 Bad Gateway

    503 Service Unavailable

    504 Gateway Timeout

    505 HTTP Version Not Supported

    506 Variant Also Negotiates

    507 Insufficient Storage

    510 Not Extended

  • 相关阅读:
    [07] Redis 持久化
    [06] Redis 事务
    [05] Jedis
    [04] Redis 配置文件
    [03] Redis 数据类型
    [02] Redis 简介&安装
    [01] NoSQL 简介
    06-NULL&typedef
    05-动态内存分配
    朴素贝叶斯分类器Naive Bayes
  • 原文地址:https://www.cnblogs.com/think8848/p/1999955.html
Copyright © 2020-2023  润新知