引言
在前后端分离的开发中,手机号绑定、验证与授权是常见的业务场景。然而,不同平台对手机号的处理规则可能不一致,且政策或系统升级可能带来临时变化。本文从工程实践角度出发,讨论如何通过TypeScript类型建模和错误码协议,设计健壮的前端表单状态机与用户反馈机制。文中示例均为通用演示,不绑定任何具体税务系统或官方接口。
核心概念区分
在手机号相关流程中,需明确三个层次:
- 持有验证:确认用户对某个手机号的控制权(如通过短信验证码)。
- 身份验证:确认用户本人的身份(如通过证件信息或生物识别)。
- 授权:由服务端依据当前主体、资源与操作判断是否允许执行该业务;它与用户同意接收通知是不同概念。
这三者可能独立发生,也可能组合出现。前端应根据错误码区分当前失败发生在哪个阶段,从而给出针对性提示。
TypeScript类型建模
状态机设计
前端表单状态可建模为:
typescript
type FormPhase = 'idle' | 'input' | 'verifying' | 'authorizing' | 'success' | 'failed';
type VerificationMethod = 'sms' | 'call' | 'appPush';
interface PhoneFormState {
phase: FormPhase;
phoneNumber: string;
verificationMethod?: VerificationMethod;
retryCount: number;
lastError?: ErrorCode;
}
错误码协议
定义错误码枚举,区分可重试与不可重试错误:
typescript
enum ErrorCode {
// 可重试:网络或临时系统问题
NETWORK_TIMEOUT = 'NETWORK_TIMEOUT',
SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',
// 可重试:验证码错误或过期
CODE_INVALID = 'CODE_INVALID',
CODE_EXPIRED = 'CODE_EXPIRED',
// 不可重试:业务规则或权限问题
PHONE_ALREADY_BOUND = 'PHONE_ALREADY_BOUND',
PHONE_NOT_ALLOWED = 'PHONE_NOT_ALLOWED',
IDENTITY_MISMATCH = 'IDENTITY_MISMATCH',
UNAUTHORIZED = 'UNAUTHORIZED',
// 未知错误
UNKNOWN = 'UNKNOWN'
}
interface ApiError {
code: ErrorCode;
message: string;
retryable: boolean;
}
注意:以上错误码名称和含义是自拟的通用演示,不代表任何真实系统的规则。实际开发中,需根据后端接口文档定义。
前端表单状态与用户反馈
状态转换逻辑
typescript
type FormEvent =
| { type: 'SUBMIT' }
| { type: 'SUCCESS' }
| { type: 'ERROR'; error: ApiError };
function transition(state: PhoneFormState, event: FormEvent): PhoneFormState {
switch (state.phase) {
case 'idle':
if (event.type === 'SUBMIT') return { ...state, phase: 'verifying' };
break;
case 'verifying':
if (event.type === 'SUCCESS') return { ...state, phase: 'authorizing' };
if (event.type === 'ERROR' && event.error.retryable) {
return { ...state, retryCount: state.retryCount + 1, lastError: event.error.code };
}
if (event.type === 'ERROR' && !event.error.retryable) {
return { ...state, phase: 'failed', lastError: event.error.code };
}
break;
case 'authorizing':
if (event.type === 'SUCCESS') return { ...state, phase: 'success' };
if (event.type === 'ERROR') return { ...state, phase: 'failed', lastError: event.error.code };
break;
}
return state;
}
用户反馈策略
- 可重试错误:显示"网络异常,请稍后重试"或"验证码错误,请重新输入",并提供重试按钮。
- 不可重试错误:显示具体原因(如"该手机号已被其他账号绑定"),并引导用户联系客服或更换手机号。
- 幂等性:前端在提交请求时携带唯一请求ID,后端据此去重,避免重复提交导致多次扣费或发送多条验证码。
注意事项
- 本文示例代码是通用演示,不涉及任何真实税务系统接口。
- 实际业务中,手机号绑定规则可能因平台而异,且可能随政策调整。请以当地官方渠道的最新说明为准。
- 不要使用他人实名手机号进行验证,也不要尝试绕过验证码机制。
- 对于办税相关功能,务必参考当地电子税务局的官方指引,以实际界面和答复为准。
结语
通过TypeScript类型建模和清晰的错误码协议,前端可以更稳健地处理手机号绑定流程中的各种异常,提升用户体验。同时,保持对业务规则变化的敏感,避免依赖未经核实的"新规"。
示例仅建模前端界面,最终授权必须由服务端判断。retryable 表示可由用户纠正输入后再次提交或有限重试,不代表应自动循环发送验证码;验证码错误不能无上限重试。