前言 代碼胡亂寫,維護火葬場! 在平時工作中遇到前同事寫介面這樣返回值 當介面返回1時,不去看他的代碼就永遠猜不到這個1代表的是返回成功還是返回值 稍微好點的 維護和改bug簡直讓人瘋狂,導致大部分時間浪費在“體會”別人返回值的邏輯中 天天加班與救bug於水火之中 合理分配前後端返回值很重要! 一般 ...
前言
代碼胡亂寫,維護火葬場!
在平時工作中遇到前同事寫介面這樣返回值
當介面返回1時,不去看他的代碼就永遠猜不到這個1代表的是返回成功還是返回值
稍微好點的
維護和改bug簡直讓人瘋狂,導致大部分時間浪費在“體會”別人返回值的邏輯中
天天加班與救bug於水火之中
合理分配前後端返回值很重要!
一般我們常用統一的格式返回json,無論後臺是運行正常還是發生異常,響應給前端的數據格式是不變的!
public class Result<T> where T : class
{
public ResultCode code { get; set; }
public string msg { get; set; }
public T data { get; set; }
}
包裝一下,通常使用構造函數
public class Result<T> where T : class
{
public ResultCode code { get; set; }
public string msg { get; set; }
public T data { get; set; }
public Result(T data)
{
code = ResultCode.Ok;
msg = ResultCode.Ok.GetDescription();
this.data = data;
}
public Result(ResultCode code, string msg, T data)
{
this.code = code;
this.msg = msg ?? code.GetDescription();
this.data = data;
}
}
這麼使用new Result<Store>(code, msg, data)
使用起來還是不夠簡化
繼續封裝
public class Result<T> where T : class
{
public ResultCode code { get; set; }
public string msg { get; set; }
public T data { get; set; }
public Result(T data)
{
code = ResultCode.Ok;
msg = ResultCode.Ok.GetDescription();
this.data = data;
}
public Result(ResultCode code, string msg, T data)
{
this.code = code;
this.msg = msg ?? code.GetDescription();
this.data = data;
}
public static Result<T> FromCode(ResultCode code, string msg = null, T data = default)
{
if (data == null)
data = (T) new Object();
return new Result<T>(code, msg, data);
}
public static Result<T> Ok(T data)
{
return new Result<T>(data);
}
public static Result<T> FromError(ResultCode code = ResultCode.Fail, string msg = null, T data = default)
{
return new Result<T>(code, msg, data);
}
}
[HttpGet]
public Result<Store> Get()
{
return Result<Store>.Ok(new Store());
}
這樣就稍微好點了
全局處理響應數據
雖然控制器返回值可以統一了,但是異常處理並沒有統一,這時候就需要建個中間件/異常過濾器進行處理異常
app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
public class GlobalExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
public GlobalExceptionHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (System.Exception ex)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "text/json;charset=utf-8;";
if (ex is ResultException == false)
{
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger<GlobalExceptionHandlerMiddleware>();
logger.LogError(1, ex, ex.Message);
}
var json = Result<object>.FromCode(ResultCode.Fail, ex.Message);
var error = JsonSerializer.Serialize(json);
await context.Response.WriteAsync(error);
}
}
}
有些異常是不需要記錄的,這時候可以自定義ResultException
進行判斷
public class ResultException : Exception
{
public ResultException(string message) : base(message)
{
}
public ResultException(string message, Exception e) : base(message, e)
{
}
}
if (ex is ResultException == false)
{
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger<GlobalExceptionHandlerMiddleware>();
logger.LogError(1, ex, ex.Message);
}
參數校驗處理
一個介面一般對參數(請求數據)都會進行安全校驗,按照之前的格式返回驗證異常。
public class ModelActionFilter : ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var errorResults = new List<ErrorResultDto>();
foreach (var item in context.ModelState)
{
var result = new ErrorResultDto
{
Field = item.Key,
Msg = "",
};
foreach (var error in item.Value.Errors)
{
if (!string.IsNullOrEmpty(result.Msg))
{
result.Msg += '|';
}
result.Msg += error.ErrorMessage;
}
errorResults.Add(result);
}
context.Result = new JsonResult(Result<List<ErrorResultDto>>.FromCode(ResultCode.InvalidData, data: errorResults));
}
}
}
public class ErrorResultDto
{
/// <summary>
/// 參數領域
/// </summary>
public string Field { get; set; }
/// <summary>
/// 錯誤信息
/// </summary>
public string Msg { get; set; }
}
Startup.cs
services.AddControllers(options =>
{
options.Filters.Add(new ModelActionFilter());
options.MaxModelValidationErrors = 50;
options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
_ => "該欄位不可為空。");
})