C#防止重复提交
C#防止重复提交
文章目录
- C#防止重复提交
- 前言
- 防止重复提交的思路
- Web API 防止重复提交
- 代码实现
- 代码讲解
- 使用方法
- MVC防止重复提交
- 总结
前言
当用户在前端进行提交数据时,如果网络出现卡顿和前端没有给出响应的话顾客通常都会狂点提交按钮,这样就很容易导致后端数据造成脏数据,众所周知顾客就是老天爷,这种问题一定是咱有问题。下面我们就来看看如何避免这种情况吧。
防止重复提交的思路
防止重复提交我们可以才用缓存的方式存储一个key在我们的Redis或者其他类型的缓存,再给它设置一个过期时间比如五秒或者三四秒,这个时间最好不要设置的过长,不然会影响用户体验。值得注意的是这个key一定要是与用户一一对应且不会重复的!
Web API 防止重复提交
代码实现
以下是具体的代码实现:
// <summary>
/// 防重复提交,api使用
/// </summary>
public class LockAttribute : ActionFilterAttribute
{
/// <summary>
/// 拦截
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
Stopwatch sw = new Stopwatch();
sw.Start();
if (GlobalContext.SystemConfig.Debug == false)
{
if (OperatorProvider.Provider.GetCurrent() == null)
{
context.Result = new JsonResult(new AlwaysResult { state = ResultType.error.ToString(), message = "抱歉,没有操作权限" });
return;
}
else
{
string token = context.HttpContext.Request.Headers[GlobalContext.SystemConfig.TokenName].ParseToString();
if (string.IsNullOrWhiteSpace(token))
{
context.Result = new JsonResult(new AlwaysResult { state = ResultType.error.ToString(), message = "token不能空" });
return;
}
//固定加锁5秒
bool result = CacheHelper.SetNx(token, token, 5);
if (!result)
{
context.Result = new JsonResult(new AlwaysResult { state = ResultType.error.ToString(), message = "请求太频繁,请稍后" });
return;
}
}
}
await next();
sw.Stop();
}
}
代码讲解
- GlobalContext.SystemConfig.Debug :这里是读取配置文件判断是否为开发环境
- OperatorProvider.Provider.GetCurrent():获取顾客在系统中的权限
- context.HttpContext.Request.Headers[GlobalContext.SystemConfig.TokenName]:这里是通过上线文获取顾客的Token
- CacheHelper.SetNx:这里是设置缓存:该方法会查询缓存中是否已有该用户的缓存信息,如果已经有了则返回false,没有就设置该用户的缓存并返回true。
使用方法
直接以特性的形似使用,在需要进行锁定的接口上标注即可
MVC防止重复提交
public class HandlerLockAttribute : ActionFilterAttribute
{
public HandlerLockAttribute()
{
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (OperatorProvider.Provider.GetCurrent() == null)
{
WebHelper.WriteCookie("WaterCloud_login_error", "overdue");
//filterContext.HttpContext.Response.WriteAsync("<script>top.location.href ='" + filterContext.HttpContext.Request.PathBase + "/Home/Error?msg=408" + "';if(document.all) window.event.returnValue = false;</script>");
OperatorProvider.Provider.EmptyCurrent("pc_").GetAwaiter().GetResult();
filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.PathBase + "/Home/Error?msg=408");
return;
}
else
{
string token = filterContext.HttpContext.Request.Cookies["pc_" + GlobalContext.SystemConfig.TokenName];
string cacheToken = CacheHelper.GetAsync<string>("pc_" + GlobalContext.SystemConfig.TokenName + "_" + OperatorProvider.Provider.GetCurrent().UserId + "_" + OperatorProvider.Provider.GetCurrent().LoginTime).GetAwaiter().GetResult();
if (string.IsNullOrWhiteSpace(token))
{
filterContext.Result = new JsonResult(new AlwaysResult { state = ResultType.error.ToString(), message = "token不能空" });
return;
}
if (string.IsNullOrWhiteSpace(cacheToken))
{
filterContext.Result = new JsonResult(new AlwaysResult { state = ResultType.error.ToString(), message = "token不能空" });
return;
}
if (token != cacheToken)
{
filterContext.Result = new JsonResult(new AlwaysResult { state = ResultType.error.ToString(), message = "请求异常" });
return;
}
//固定加锁5秒
bool result = CacheHelper.SetNx(token, token, 5);
if (!result)
{
filterContext.Result = new JsonResult(new AlwaysResult { state = ResultType.error.ToString(), message = "请求太频繁,请稍后" });
return;
}
}
//随机值
base.OnActionExecuting(filterContext);
}
}
- OperatorProvider.Provider.EmptyCurrent(“pc_”).GetAwaiter().GetResult():此处是判断如果顾客信息为空的话就清空当前登录账户的缓存
- CacheHelper.SetNx:这里是设置缓存:该方法会查询缓存中是否已有该用户的缓存信息,如果已经有了则返回false,没有就设置该用户的缓存并返回true。
总结
这里主要是通过过滤器实现的。这里顺带提一下,过滤器也属于是AOP编程的体现哦。今日的分享就到此结束,有什么不懂的可以留言讨论。