.NET Core Razor Pages实现.cshtml表单校验通过才可提交的问题修复
问题根因
你的表单校验无法阻止提交,核心是4个逻辑错误:
- 单字段校验函数返回值逻辑完全混乱:比如
fname()检测到名字为空(校验失败)时返回true,校验通过反而返回false;密码相关的checkpass1/checkpass2又反过来,校验失败返回false、通过返回true,用&&做联合判断时结果完全不可控 - 全局
count变量存在覆盖问题:前一个字段校验失败把count设为1,后一个字段校验通过又会把count改回0,导致漏判错误 validate()函数没有拦截浏览器默认提交行为:就算检测到错误,浏览器还是会正常发送POST请求- 后端校验失败返回页面时,没有重新加载国家下拉列表数据,会导致下拉框选项清空
修复步骤
1. 统一前端单字段校验逻辑
删掉全局无用的var count=0变量,所有单字段校验统一规则:校验通过返回true,校验失败返回false,替换原有的校验函数代码:
const fname = () => { const inputVal = document.getElementById("signUpFirstName").value.trim(); const errorSpan = document.querySelector("#l1 span"); if (inputVal.length === 0) { errorSpan.innerHTML = "Please Enter Your First Name"; errorSpan.style.color = "red"; return false; } errorSpan.innerHTML = ""; return true; } const lname = () => { const inputVal = document.getElementById("signUpLastName").value.trim(); const errorSpan = document.querySelector("#l2 span"); if (inputVal.length === 0) { errorSpan.innerHTML = "Please Enter Your Last Name"; errorSpan.style.color = "red"; return false; } errorSpan.innerHTML = ""; return true; } const checkcountry = () => { const inputVal = document.getElementById("signUpCountryCode").value.trim(); const errorSpan = document.querySelector("#l3 span"); if (inputVal.length === 0) { errorSpan.innerHTML = "Please Enter Your Country"; errorSpan.style.color = "red"; return false; } errorSpan.innerHTML = ""; return true; } const checkMobile = () => { const inputVal = document.getElementById("signUpMobileNumber").value.trim(); const errorSpan = document.querySelector("#i4 span"); const phonenoReg = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/; if (!phonenoReg.test(inputVal)) { errorSpan.innerHTML = "Please Enter a valid Mobile No."; errorSpan.style.color = "red"; return false; } errorSpan.innerHTML = ""; return true; } const checkEmail = () => { const inputVal = document.getElementById("signUpEmail").value.trim(); const emailReg = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; const errorSpan = document.querySelector("#i5 span"); if (!emailReg.test(inputVal)) { errorSpan.innerHTML = "Please Enter a valid Email id."; errorSpan.style.color = "red"; return false; } errorSpan.innerHTML = ""; return true; } const checkpass1 = () => { const inputVal = document.getElementById("signUpPassword").value; const errorSpan = document.querySelector("#i6 span"); const specialCharReg = /[`!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/; if (inputVal.length < 8) { errorSpan.innerHTML = "Password length must be atleast 8 characters"; errorSpan.style.color = "red"; return false; } if (inputVal.length > 12) { errorSpan.innerHTML = "Password length must not exceed 12 characters"; errorSpan.style.color = "red"; return false; } if (!specialCharReg.test(inputVal)) { errorSpan.innerHTML = "Password must contain atleast 1 special character"; errorSpan.style.color = "red"; return false; } errorSpan.innerHTML = ""; return true; } const checkpass2 = () => { const confirmVal = document.getElementById("signUpConfirmPassword").value; const passwordVal = document.getElementById("signUpPassword").value; const errorSpan = document.querySelector("#i7 span"); if (confirmVal !== passwordVal) { errorSpan.innerHTML = "Password does not match"; errorSpan.style.color = "red"; return false; } errorSpan.innerHTML = ""; return true; }
2. 绑定表单提交事件,拦截非法提交
首先给form标签加id,同时删掉提交按钮上的onclick="validate()"属性:
<form class="mb-3" method="post" id="signUpForm">
替换原有的validate()函数,直接监听表单的submit事件,校验失败时阻止默认提交行为:
const validate = (e) => { const isAllValid = fname() && lname() && checkcountry() && checkMobile() && checkEmail() && checkpass1() && checkpass2(); if (!isAllValid) { e.preventDefault(); console.log("校验失败,阻止表单提交"); return false; } console.log("校验通过,允许提交"); return true; } // 绑定表单提交事件 document.getElementById("signUpForm").addEventListener("submit", validate);
3. 修复后端校验逻辑
补全空值判断,校验失败返回页面时重新加载下拉列表数据,避免控件清空,替换原有的OnPost方法:
public async Task<IActionResult> OnPost() { // 加载国家下拉列表公共逻辑 async Task LoadCountryList() { if (!_memoryCache.TryGetValue("CountryList", out List<MasterDataContent> cacheValue)) { var countryList = await this._masterData.GetData("MasterDataItems/GetCountry", ""); cacheValue = countryList; _memoryCache.Set("CountryList", cacheValue, SoraCacheManager.ThreeHunderedSecondsCache()); } signUp ??= new SignUpPageVM(); signUp.CountryList = new SelectList(cacheValue, "key", "value"); } if (!ModelState.IsValid || signUp == null) { await LoadCountryList(); return Page(); } if (signUp.ConfirmPassword != signUp.Password) { ModelState.AddModelError(string.Empty, "两次输入的密码不一致"); await LoadCountryList(); return Page(); } UserSignUpRequestDTO signUpRequest = new UserSignUpRequestDTO { FirstName = signUp.FirstName, LastName = signUp.LastName, MobileNumber = signUp.MobileNumber, Email = signUp.Email, CountryCode = signUp.CountryCode, Password = signUp.Password }; var response = await this._webClient!.PostData("User/SignUp", signUpRequest); return RedirectToPage("Login"); }
注意:前端JS校验仅用于提升用户体验,后端校验必须保留,用户可以直接禁用JS绕过前端校验。
内容的提问来源于stack exchange,提问作者Naman Garg
相关产品推荐
相关产品推荐

