前端请求被限频了怎么办?怎么处理接口频率限制?
我最近在做登录功能,连续输错几次密码后,后端返回 429 Too Many Requests,但前端没做任何提示或限制。用户根本不知道要等多久才能再试,体验很差。我想在前端加个倒计时提示,但不确定该怎么设计样式和交互。
比如输错三次后,按钮变成禁用状态,并显示“请60秒后再试”。下面是我试着写的按钮状态样式:
.btn-rate-limited {
background: #ccc;
color: #666;
cursor: not-allowed;
position: relative;
}
.btn-rate-limited::after {
content: "请60秒后再试";
position: absolute;
top: 100%;
left: 0;
width: 100%;
font-size: 12px;
color: #999;
}
但这样写感觉不够灵活,时间没法动态更新。有没有更合理的做法?是不是应该用 JavaScript 控制倒计时,而不是纯 CSS?
服务端返回 429 的时候,应该顺便带上重试时间,比如响应头里带
Retry-After字段,或者响应体里返回retry_after: 60这种字段。前端拿到这个时间,才能准确倒计时,而不是写死 60 秒。实际开发里,建议这样处理:
1. 登录请求拦截器里,统一处理 429 状态码
2. 拿到重试时间后,设置按钮为禁用状态,启动定时器,每秒减一,显示剩余时间
3. 倒计时结束自动恢复按钮状态
举个简单例子(假设后端返回 retry_after 字段):
HTML 部分就简单加个占位元素:
CSS 样式你原来那套可以保留,但倒计时文本别写死在
::after里,用 JS 动态插文本更靠谱。另外注意防抖和节流,别用户狂点按钮导致前端自己先崩了。最后提醒一句:前端限频只是体验优化,真正安全还得靠服务端做频率限制和 IP 拦截,别让前端兜底太多。
Retry-After头,后端应该会返回等待时间(单位是秒),这个值比硬编码 60 更靠谱。建议这么干:
首先,前端在提交登录请求前,先查一下本地有没有一个“锁”的状态,比如用
localStorage存个rateLimitUntil时间戳,如果当前时间还没到,就直接禁用按钮并提示剩余时间,不用发请求。如果请求返回 429,就从响应头里读
Retry-After,没的话再 fallback 到默认值比如 60 秒。然后 JS 启一个定时器,每秒更新按钮文字,比如“请59秒后再试”,直到倒计时结束,恢复按钮可用状态。
代码大概长这样:
CSS 你可以保留你原来的样式,但把那个静态的
::after内容删掉,改用 JS 控制按钮的文本内容就行,比如:这样按钮内容能动态更新,体验也更自然。而且万一后端限频时间变了,你也不用改前端代码,直接用
Retry-After就行。对了,记得别把倒计时逻辑写太复杂,别让用户看到“请1秒后重试”这种奇怪的 1.001 秒,统一向上取整比较友好。