解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
5.36 KiB
X
using System.Net;
using NewLife.Collections;
using NewLife.Data;
using NewLife.Remoting;
using NewLife.Serialization;

namespace NewLife.Http;

/// <summary>Http响应</summary>
public class HttpResponse : HttpBase
{
    #region 属性
    /// <summary>状态码</summary>
    public HttpStatusCode StatusCode { get; set; } = HttpStatusCode.OK;

    /// <summary>状态描述</summary>
    public String? StatusDescription { get; set; }
    #endregion

    /// <summary>分析第一行</summary>
    /// <param name="firstLine"></param>
    protected override Boolean OnParse(String firstLine)
    {
        if (firstLine.IsNullOrEmpty()) return false;

        // HTTP/1.1 502 Bad Gateway
        if (!firstLine.StartsWith("HTTP/")) return false;

        var ss = firstLine.Split(' ');
        //if (ss.Length < 3) throw new Exception("非法响应头 {0}".F(firstLine));
        if (ss.Length < 3) return false;

        Version = ss[0].TrimPrefix("HTTP/");

        // 分析响应码
        var code = ss[1].ToInt();
        if (code > 0) StatusCode = (HttpStatusCode)code;

        StatusDescription = ss.Skip(2).Join(" ");

        return true;
    }

    /// <summary>创建请求响应包。非成功状态且无主体时使用状态描述作为主体</summary>
    /// <returns></returns>
    public override IOwnerPacket Build()
    {
        // 如果响应异常,则使用响应描述作为内容
        if (StatusCode > HttpStatusCode.OK && Body == null && !StatusDescription.IsNullOrEmpty())
        {
            Body = (ArrayPacket)StatusDescription.GetBytes();
        }

        return base.Build();
    }

    /// <summary>创建头部</summary>
    /// <param name="length"></param>
    /// <returns></returns>
    protected override String BuildHeader(Int32 length)
    {
        // 构建头部
        var sb = Pool.StringBuilder.Get();
        sb.AppendFormat("HTTP/{2} {0} {1}\r\n", (Int32)StatusCode, StatusDescription ?? StatusCode.ToString(), Version);

        //// cors
        //sb.AppendFormat("Access-Control-Allow-Origin:{0}\r\n", "*");
        //sb.AppendFormat("Access-Control-Allow-Methods:{0}\r\n", "POST, GET");
        //sb.AppendFormat("Access-Control-Allow-Headers:{0}\r\n", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");

        // 内容长度:存在主体明确长度;否则除非 Transfer-Encoding/Upgrade 才可省略,默认发送 0
        if (length > 0)
            Headers["Content-Length"] = length + "";
        else if (!Headers.ContainsKey("Transfer-Encoding") && !Headers.ContainsKey("Upgrade"))
            Headers["Content-Length"] = "0";

        if (!ContentType.IsNullOrEmpty()) Headers["Content-Type"] = ContentType;

        foreach (var item in Headers)
        {
            sb.AppendFormat("{0}: {1}\r\n", item.Key, item.Value);
        }

        sb.Append("\r\n");

        return sb.Return(true);
    }

    /// <summary>验证,如果失败则抛出异常</summary>
    public void Valid()
    {
        if (StatusCode != HttpStatusCode.OK) throw new Exception(StatusDescription ?? (StatusCode + ""));
    }

    /// <summary>设置结果,影响Body和ContentType</summary>
    /// <param name="result">业务结果或异常</param>
    /// <param name="contentType">指定内容类型,缺省时按类型推断</param>
    public void SetResult(Object result, String? contentType = null)
    {
        if (result == null) return;

        switch (result)
        {
            case Exception ex:
                SetExceptionResult(ex);
                return;
            case ISpanSerializable span:
                contentType ??= "application/octet-stream";
                Body = span.ToPacket();
                break;
            case IAccessor accessor:
                contentType ??= "application/octet-stream";

                var ms = new MemoryStream();
                accessor.Write(ms, null);
                ms.Position = 0;
                Body = new ArrayPacket(ms);
                break;
            case IPacket pk:
                contentType ??= "application/octet-stream";
                Body = pk;
                break;
            case Byte[] buffer:
                contentType ??= "application/octet-stream";
                Body = (ArrayPacket)buffer;
                break;
            case Stream stream:
                contentType ??= "application/octet-stream";
                Body = (ArrayPacket)stream.ReadBytes(-1);
                break;
            case String str:
                contentType ??= "text/html";
                Body = (ArrayPacket)str.GetBytes();
                break;
            default:
                contentType ??= "application/json";
                Body = (ArrayPacket)result.ToJson().GetBytes();
                break;
        }

        if (ContentType.IsNullOrEmpty()) ContentType = contentType;
    }

    /// <summary>设置异常结果,自动映射ApiException到对应状态码</summary>
    /// <param name="ex">异常</param>
    private void SetExceptionResult(Exception ex)
    {
        if (ex is ApiException aex)
            StatusCode = (HttpStatusCode)aex.Code;
        else
            StatusCode = HttpStatusCode.InternalServerError;

        StatusDescription = ex.Message;
    }

    /// <summary>已重载。</summary>
    /// <returns></returns>
    public override String ToString() => $"HTTP/{Version} {(Int32)StatusCode} {StatusDescription ?? (StatusCode + "")}";
}