2.接口输入校验、输出格式、及异常处理——SnailAspNetCoreFramework快速开发框架之后端设计
输入校验
- 在控制器上加上[ApiController]特性,让接口自动校验模型,不必再调用ModelState.IsValid
- 一般的校验,用自带的校验Attribute即可,如Required,StringLength,Range,RegularExpression等
- 示例如下
/// <summary>
/// dto输入校验
/// </summary>
/// <remarks>
/// 可参考:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-3.1
/// </remarks>
public class DtoValidateSample : IDto, IValidatableObject
{
[Required(ErrorMessage ="必填")]
public string Reqired { get; set; }
[StringLength(8, ErrorMessage = "长度不能超过8")]
public string StringLen { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var errors = new List<ValidationResult>();
#region 这里写dto的校验逻辑,如果有问题则加入到errors里
//errors.Add(new ValidationResult("这是错误内容",new List<string> { "这是核验不通过的字段" }));
#endregion
return errors;
}
}
统一输出格式
- 格式约定如下
{
"Code":2000,//这是接口的状态,只有2000才为成功,其它为失败,失败的原因为msg
"Data":xxx,//这是真实返回的数据
"Msg":""//错误信息
}
- 用ResultFilter实现,在所有的接口返回结果时,统一对结果进行标准格式封闭,GlobalResultFilterAttribute
/// <summary>
/// 只有没有进入到ExceptFilter里的才会进入此过滤器
/// </summary>
public class GlobalResultFilterAttribute : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is ObjectResult objectResult)//正常返回
{
context.Result = new ObjectResult(ApiResultDto.SuccessResult(objectResult.Value));
}
else if (context.Result is EmptyResult emptyResult)
{
context.Result = new ObjectResult(ApiResultDto.SuccessResult(null));
}
}
}
- 将GlobalResultFilterAttribute加入到全局过滤器
- action只需正常返回Data里的类型值即可
异常处理
- 通常我们项目中的异常会分几种,
1、业务上的自己定义的异常信息(本文暂称它为业务异常),这些异常信息通常都是要给用户看的。
2、未捕获的程序异常(本文暂称它为程序异常),这类异常要在开发环境让开发者看到,但在生产环境时,会隐藏异常的详细信息 - 通常会在如下几个地方对上面的异常进行处理
1、在MVC管道里
2、在asp.net core管道里
下面是两个管道里处理这两种异常的代码
MVC管道处理异常
在接口或接口调用的方法里如果手动throw BusinessException(BusinessException为业务异常的类),会被MVC管理捕获
public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
{
private ILogger _logger;
public GlobalExceptionFilterAttribute(ILogger<GlobalExceptionFilterAttribute> logger)
{
_logger = logger;
}
public override void OnException(ExceptionContext context)
{
if (context.Exception is BusinessException businessException)
{
// 业务类的异常,返回4000状态,并返回异常内容。模型校验也会返回4000状态和内容
context.Result = new ObjectResult(ApiResultDto.BadRequestResult(businessException.Message));
if (_logger != null)
{
_logger.LogWarning(businessException, "businessException");
}
}
else
{
context.Result = new ObjectResult(ApiResultDto.ServerErrorResult("未知异常"));
if (_logger != null)
{
_logger.LogError("exception:{exception} \n innerException:{innerException}", context.Exception?.ToString(), context.Exception?.InnerException?.ToString());
}
}
}
}
asp.net core管道处理异常
asp.net core 的管理配置是在Startup.cs的Configure方法里,管道异常处理代码如下
//开发环境用异常处理程序页,让开发者能看到异常信息详细
if (env.IsDevelopment())
{
app.UseMiniProfiler();
app.UseDeveloperExceptionPage(); //开发环境用异常处理程序页,让开发者能看到异常信息详细
}
else
{
// 生产环境异常处理,隐藏异常详细信息,并记录日志
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var loggerFactory = (ILoggerFactory)context.RequestServices.GetService(typeof(ILoggerFactory));
var logger = loggerFactory.CreateLogger("UnKnowException");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
//业务异常
ApiResultDto responseResultModel;
if (exceptionHandlerPathFeature?.Error is BusinessException businessException)
{
responseResultModel = ApiResultDto.BadRequestResult(businessException.Message);
if (logger != null)
{
logger.LogError(exceptionHandlerPathFeature?.Error?.ToString());
}
}
else
{
responseResultModel = ApiResultDto.BadRequestResult($"程序出错,出于安全考虑,出错信息未能返回,请联系IT进行处理,错误时间{DateTime.Now}");
if (logger != null)
{
logger.LogError(exceptionHandlerPathFeature?.Error?.ToString());
}
}
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.OK;
await context.Response.WriteAsync(JsonConvert.SerializeObject(responseResultModel));
});
});
//HTTP严格传输安全 让网站可以通知浏览器它不应该再使用HTTP加载该网站,而是自动转换该网站的所有的HTTP链接至更安全的HTTPS。它包含在HTTP的协议头 Strict-Transport-Security 中,在服务器返回资源时带上,换句话说,它告诉浏览器将URL协议从HTTP更改为HTTPS(会更安全),并要求浏览器对每个请求执行此操作。
//正式环境官方建议用UseHsts和UseHttpsRedirection,
// 如果反方代理服务器,如ngix已经有配置过http重定向https或是设置hsts,则不需要设置这两句
//参考: https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-3.1&tabs=visual-studio
app.UseHsts();
app.UseHttpsRedirection();//将所有的http重定向https
}