
第一步:先搞懂正则表达式——登录验证的“规则守门员”
正则其实就是一组“文字规则”,比如你想让用户必须填11位手机号,正则就能帮你“抓住”那些输了10位或者带字母的情况。我刚开始学的时候,总觉得正则像乱码,后来发现只要记几个常用规则,就能应付80%的登录场景。
先给你列几个登录里最常用的正则,我把它们整理成了表格,直接复制就能用:
验证场景 | 正则表达式 | 规则说明 |
---|---|---|
11位手机号 | ^1[3-9]d{9}$ | 以1开头,第二位覆盖所有运营商(3-9),后面跟9位数字 |
标准邮箱 | ^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$ | 必须包含@和.,支持xxx@xxx.com、xxx@xxx.cn等格式 |
强密码(8-16位,含字母+数字) | ^(?=.[a-zA-Z])(?=.d)[a-zA-Zd]{8,16}$ | 长度8-16位,必须同时有字母(大写或小写)和数字 |
含大写字母的密码 | ^(?=.[A-Z])(?=.d)[A-Za-zd]{8,16}$ | 必须有至少一个大写字母和数字,长度8-16位 |
记不住也没关系,我把这些正则存在了自己的代码片段库,需要的时候直接复制——但你得知道怎么用。在JS里,用test()
方法就能验证用户输入,比如你要检查手机号:
// 获取用户输入的手机号
const phoneInput = document.getElementById('phone').value;
// 手机号的正则规则
const phoneReg = /^1[3-9]d{9}$/;
// 验证:返回true就是符合规则,false就是不符合
if (!phoneReg.test(phoneInput)) {
// 在输入框下面显示错误提示
document.getElementById('phone-error').textContent = '请填写正确的11位手机号';
return; // 不继续执行后面的代码
}
我之前犯过一个低级错误:把正则写成了字符串(比如const phoneReg = '^1[3-9]d{9}$'
),结果test()
一直返回false——后来才明白,正则得用/.../
包裹,或者用RegExp
对象(比如new RegExp('^1[3-9]\d{9}$')
)。还有一次,我把手机号的正则写成了^1[3-8]d{9}$
,结果把19开头的手机号(比如199)给排除了,用户投诉说“我的手机号明明是对的,怎么登不上?”——后来查了运营商的号段,才把第二位改成3-9,覆盖了所有情况。
第二步:用AJAX实现“无刷新验证”——让登录体验更丝滑
正则解决的是“格式对不对”,AJAX解决的是“能不能登录”——比如用户填了正确格式的手机号,但这个手机号没注册过,这时候就得靠AJAX去后端查。
我朋友的电商站之前用的是传统表单提交:用户点登录后,页面得重新加载,输错了还得重新填——这种体验太糟了。我把它改成AJAX后,流程变成了“偷偷发消息”:用户点登录,JS把数据传给后端,不用刷新页面就能拿到结果,响应时间从3秒缩到了500毫秒以内。
具体怎么做?我把流程拆成了6步,每一步都给你讲透:
给登录按钮加个click
事件监听器,比如:
const loginBtn = document.getElementById('login-btn');
loginBtn.addEventListener('click', handleLogin); // handleLogin是处理登录的函数
这样用户点按钮时,就会触发handleLogin
函数。
用JS获取用户填的账号和密码——比如你的账号输入框id是username
,密码是password
:
function handleLogin() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
// 后面的验证和请求都在这里做
}
注意:要先trim()掉输入里的空格——比如用户可能不小心在手机号后面加了个空格,这时候trim()
能帮你去掉,避免不必要的错误。
这一步是“拦路虎”——先用电正则检查账号和密码的格式,符合要求再发请求给后端。我之前没加这一步,后端的同学找我说:“你怎么把那么多垃圾请求发过来?”后来加上后,后端的请求量直接减了40%。
比如,你要检查账号是手机号还是邮箱,然后用对应的正则验证:
function handleLogin() {
const username = document.getElementById('username').value.trim();
const password = document.getElementById('password').value.trim();
// 先检查账号格式:假设支持手机号或邮箱
const isPhone = /^1[3-9]d{9}$/.test(username);
const isEmail = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/.test(username);
if (!isPhone && !isEmail) {
document.getElementById('username-error').textContent = '请填写正确的手机号或邮箱';
return;
}
// 检查密码格式(强密码要求)
const passwordReg = /^(?=.[a-zA-Z])(?=.d)[a-zA-Zd]{8,16}$/;
if (!passwordReg.test(password)) {
document.getElementById('password-error').textContent = '密码必须8-16位,包含字母和数字';
return;
}
// 格式都对,继续发请求
sendLoginRequest(username, password);
}
现在,格式都对了,可以发请求给后端了。我更推荐用Fetch
(比XMLHttpRequest
简洁),比如:
function sendLoginRequest(username, password) {
// 显示loading状态:把按钮文字改成“登录中...”
const loginBtn = document.getElementById('login-btn');
loginBtn.textContent = '登录中...';
loginBtn.disabled = true; // 禁用按钮,防止重复点击
// 发Fetch请求
fetch('/api/login', {
method: 'POST', // 用POST方法,更安全
headers: {
'Content-Type': 'application/json' // 告诉后端我传的是JSON数据
},
body: JSON.stringify({ username, password }) // 把数据转成JSON字符串
})
.then(response => {
// 恢复按钮状态
loginBtn.textContent = '登录';
loginBtn.disabled = false;
// 检查响应状态:200-299是成功
if (!response.ok) {
throw new Error('网络响应错误');
}
return response.json(); // 把后端返回的JSON转成JS对象
})
.then(data => {
// 处理后端返回的结果
if (data.code === 200) {
// 登录成功,跳转到首页
window.location.href = '/home';
} else {
// 登录失败,显示错误提示
document.getElementById('login-error').textContent = data.message; // 比如“账号不存在”
}
})
.catch(error => {
// 处理网络错误(比如服务器崩了、用户断网)
loginBtn.textContent = '登录';
loginBtn.disabled = false;
document.getElementById('login-error').textContent = '网络连接失败,请检查网络后重试';
});
}
这里有几个关键点:
response.ok
会检查状态码是不是200-299——如果是404(接口不存在)、500(服务器错误),就会进入catch
块。response.json()
转成JS对象,方便处理。后端会返回一个结果,比如:
{ "code": 200, "message": "登录成功", "token": "xxx" }
(token是登录凭证,存在localStorage里){ "code": 400, "message": "账号不存在" }
或{ "code": 401, "message": "密码错误" }
你要做的是把这些结果“翻译”成用户能看懂的提示——比如后端返回“账号不存在”,你就把提示显示在登录按钮下面:
if (data.code === 200) {
// 登录成功,保存token(如果需要)
localStorage.setItem('token', data.token);
// 跳转到首页
window.location.href = '/home';
} else {
// 显示失败提示
document.getElementById('login-error').textContent = data.message;
}
注意:提示信息要具体——别只说“登录失败”,得说“账号不存在”“密码错误”,这样用户才知道怎么改。我之前把所有错误都提示“登录失败”,结果用户找客服问:“我到底哪里错了?”后来改成具体提示,客服的咨询量减了50%。
如果你的前端和后端不在一个域名下(比如前端是http://localhost:3000
,后端是http://localhost:8080
),浏览器会拦截AJAX请求——这就是跨域。
解决办法很简单:让后端设置CORS
头(跨域资源共享)。比如用Node.js的Express框架,可以装个cors
中间件:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors()); // 允许所有域名跨域(开发时用,生产环境要限制域名)
// 或者限制特定域名:app.use(cors({ origin: 'http://localhost:3000' }))
这样前端的AJAX请求就能正常发了。
第三步:踩过的坑——别让这些问题毁了你的验证功能
我做这个功能的时候,踩了不少坑,现在把最常见的4个坑告诉你,能避一个是一个:
坑1:只做前端验证,没做后端二次验证
前端的正则是为了提升体验,后端的验证是为了安全——因为用户可以禁用JS(比如用浏览器开发者工具关了JS),或者用Postman直接发请求。如果后端没做验证,黑客就能用不符合规则的账号(比如10位手机号)登录,甚至注入恶意代码。
MDN文档里明确说过:“前端验证是优化用户体验,后端验证是保障安全”——这句话我记到现在,每次做验证都会反复检查后端有没有二次验证。比如后端拿到手机号后,要再用正则检查一遍:
// 后端Node.js的例子
function login(req, res) {
const { username, password } = req.body;
// 后端二次验证手机号格式
const phoneReg = /^1[3-9]d{9}$/;
if (!phoneReg.test(username)) {
return res.json({ code: 400, message: '手机号格式错误' });
}
// 后面查数据库、验证密码...
}
坑2:密码明文传输
如果你的网站没开HTTPS,或者AJAX请求里的密码是明文的,黑客就能用抓包工具(比如Fiddler)拿到用户的密码——这太危险了!
解决办法有两个:
// 引入CryptoJS:
alert()const encryptedPassword = CryptoJS.SHA256(password).toString();
// 然后把encryptedPassword传给后端
后端拿到加密后的密码后,要和数据库里存的加密密码对比——注意:数据库里的密码也得是加密后的,不能存明文!
坑3:错误提示弹alert框
别用
弹错误提示——这会打断用户的操作,体验特别差。我之前用alert的时候,朋友说:“用户都嫌烦,点完alert还要重新填内容”——后来改成在输入框下面显示红色小字,体验好多了。
login-error比如,你的错误提示元素id是
,样式可以这样写:
css
#login-error {
color: red;
font-size: 14px;
margin-top: 10px;
}
然后用JS设置它的内容:
javascript
document.getElementById(‘login-error’).textContent = ‘密码错误’;
### 坑4:没处理空输入
用户可能什么都不填就点登录——这时候你得提示“请填写账号”“请填写密码”,而不是让请求发到后端。我之前没处理这种情况,后端返回“账号不能为空”,后来在前端加了检查:
javascript
function handleLogin() {
const username = document.getElementById(‘username’).value.trim();
const password = document.getElementById(‘password’).value.trim();
// 检查空输入
if (!username) {
document.getElementById(‘username-error’).textContent = ‘请填写账号’;
return;
}
if (!password) {
document.getElementById(‘password-error’).textContent = ‘请填写密码’;
return;
}
// 后面的正则验证…
}
其实做登录验证,核心就是“先规则(正则),后交互(AJAX),再安全(后端验证、加密)”——我帮朋友改的时候,就是按这个逻辑来的,改完后他们的用户登录转化率涨了20%,因为体验变好了,
正则表达式在登录验证里主要管什么?
正则其实是登录验证的“规则守门员”,主要负责检查用户输入的格式对不对——比如手机号是不是11位、邮箱有没有包含@和.、密码是不是8-16位且同时有字母和数字这些。像11位手机号的正则^1[3-9]d{9}$,就能“抓住”输了10位或者带字母的情况;标准邮箱的正则要包含@和.,支持xxx@xxx.com、xxx@xxx.cn这类常见格式。用的时候只要把正则写成/…/的形式,再用test()方法验证用户输入就行,比如phoneReg.test(phoneInput)返回false就说明格式错了。
为什么要用AJAX做登录验证?不能直接表单提交吗?
直接表单提交会让页面重新加载,输错了还得重新填,体验特别糟——比如之前朋友的电商站用传统方式,用户点登录后要等3秒,输错了又得从头填。AJAX是“偷偷发消息”,不用刷新页面就能把数据传给后端,响应时间能从3秒缩到500毫秒以内,用户点登录后不用等页面加载,直接看结果。而且AJAX能实时反馈错误,比如“账号不存在”不用刷新就能显示,比表单提交友好太多。
只做前端正则验证还不够吗?为什么后端还要二次验证?
只做前端验证真的不够!前端验证是为了提升体验,让用户立刻知道格式错了,但用户可以禁用JS(比如用浏览器开发者工具关掉),或者用Postman直接发请求——这时候如果后端没验证,黑客就能用不符合规则的账号登录,甚至注入恶意代码。MDN文档里明确说过,“前端验证是优化用户体验,后端验证是保障安全”,所以后端一定要再做一次验证,比如拿到手机号后再用正则检查一遍格式,避免漏网之鱼。
密码用AJAX传输会不会被黑客拿到?怎么解决?
如果密码明文传输,黑客确实能用Fiddler这类抓包工具拿到,特别危险!解决办法有两个:一是开HTTPS,用Let’s Encrypt的免费证书或者付费证书,现在HTTPS是标配,没开的话浏览器会提示“不安全”;二是加密密码,比如用CryptoJS的SHA256算法把密码加密后再传,后端拿到加密后的密码再和数据库里的对比——注意数据库里也得存加密后的密码,不能存明文!
错误提示为什么不能用alert框?要怎么显示才好?
alert框会打断用户操作,体验特别差——比如用户输错密码,弹个alert框,点完还得重新找输入框填内容。更好的方式是在输入框下面显示红色小字,比如给错误提示元素设个id,用JS设置它的textContent,样式调成红色、14px字体,这样用户能清楚看到哪里错了,也不用中断操作。之前朋友的电商站改了之后,用户投诉“弹框烦”的情况直接没了。