|
|
@ -3,3 +3,215 @@ description: |
|
|
|
globs: |
|
|
|
globs: |
|
|
|
alwaysApply: false |
|
|
|
alwaysApply: false |
|
|
|
--- |
|
|
|
--- |
|
|
|
|
|
|
|
# 社交登录错误码映射指南 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 错误码说明 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 微信小程序登录错误码 |
|
|
|
|
|
|
|
# 社交登录错误码映射指南 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 错误码说明 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 微信小程序登录错误码 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 错误码 | 错误信息 | 前端处理建议 | |
|
|
|
|
|
|
|
|--------|----------|--------------| |
|
|
|
|
|
|
|
| 1002018000 | 社交授权失败,原因是:{} | 显示具体错误原因,引导用户重试 | |
|
|
|
|
|
|
|
| 1002018001 | 社交授权失败,找不到对应的用户 | 提示用户账号未绑定,引导注册或绑定 | |
|
|
|
|
|
|
|
| 1002018002 | 微信授权码已过期,请重新授权 | 自动调用 `uni.login()` 重新获取 code | |
|
|
|
|
|
|
|
| 1002018003 | 微信授权码无效或已被使用 | 清除本地存储的 code,重新获取 | |
|
|
|
|
|
|
|
| 1002018005 | 微信服务器连接失败,请稍后重试 | 提示网络问题,延迟后重试 | |
|
|
|
|
|
|
|
| 1002018006 | 用户身份验证失败,请重新登录 | 清除本地 token,跳转登录页 | |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 参数验证说明 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 使用 @Valid 注解进行参数验证 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在控制器方法中使用 `@Valid` 注解时,Spring 会自动验证请求对象的字段: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
|
|
|
@PostMapping("/app_login") |
|
|
|
|
|
|
|
public CommonResult<AuthLoginRespVO> AppLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) { |
|
|
|
|
|
|
|
// 不需要手动检查 code、type、state 是否为空 |
|
|
|
|
|
|
|
// @Valid 会根据 AuthSocialLoginReqVO 中的注解自动验证 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`AuthSocialLoginReqVO` 中的验证规则: |
|
|
|
|
|
|
|
- `code`: `@NotEmpty(message = "授权码不能为空")` |
|
|
|
|
|
|
|
- `type`: `@NotNull(message = "社交平台的类型不能为空")` |
|
|
|
|
|
|
|
- `state`: `@NotEmpty(message = "state 不能为空")` |
|
|
|
|
|
|
|
- `openid`: 无验证注解(需要手动验证) |
|
|
|
|
|
|
|
- `userType`: 无验证注解 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**注意**:当参数验证失败时,Spring 会自动返回 400 Bad Request 错误,包含详细的验证错误信息。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 前端错误处理示例 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```javascript |
|
|
|
|
|
|
|
// 在 store/modules/user.js 中优化错误处理 |
|
|
|
|
|
|
|
Login({ commit }, userInfo) { |
|
|
|
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
|
|
|
login(userInfo).then(res => { |
|
|
|
|
|
|
|
const { data } = res |
|
|
|
|
|
|
|
setToken(data) |
|
|
|
|
|
|
|
resolve() |
|
|
|
|
|
|
|
}).catch(error => { |
|
|
|
|
|
|
|
// 根据错误码进行不同处理 |
|
|
|
|
|
|
|
const errorCode = error.code |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch(errorCode) { |
|
|
|
|
|
|
|
case '1002018002': // code 过期 |
|
|
|
|
|
|
|
// 重新获取 code |
|
|
|
|
|
|
|
uni.login({ |
|
|
|
|
|
|
|
success: (res) => { |
|
|
|
|
|
|
|
setOpenId(res.code) |
|
|
|
|
|
|
|
// 重试登录 |
|
|
|
|
|
|
|
this.dispatch('Login', { |
|
|
|
|
|
|
|
...userInfo, |
|
|
|
|
|
|
|
code: res.code |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case '1002018003': // code 无效 |
|
|
|
|
|
|
|
// 清除本地 code |
|
|
|
|
|
|
|
removeOpenId() |
|
|
|
|
|
|
|
uni.showModal({ |
|
|
|
|
|
|
|
title: '提示', |
|
|
|
|
|
|
|
content: '授权信息无效,请重新进入小程序', |
|
|
|
|
|
|
|
showCancel: false, |
|
|
|
|
|
|
|
success: () => { |
|
|
|
|
|
|
|
// 可以选择重启小程序 |
|
|
|
|
|
|
|
uni.reLaunch({ |
|
|
|
|
|
|
|
url: '/pages/login' |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case '1002018005': // 网络错误 |
|
|
|
|
|
|
|
uni.showToast({ |
|
|
|
|
|
|
|
title: '网络连接失败,请稍后重试', |
|
|
|
|
|
|
|
icon: 'none', |
|
|
|
|
|
|
|
duration: 2000 |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
// 延迟后重试 |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
this.dispatch('Login', userInfo) |
|
|
|
|
|
|
|
}, 3000) |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
// 显示默认错误信息 |
|
|
|
|
|
|
|
uni.showToast({ |
|
|
|
|
|
|
|
title: error.message || '登录失败', |
|
|
|
|
|
|
|
icon: 'none' |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reject(error) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 最佳实践 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 避免 code 重复使用 |
|
|
|
|
|
|
|
```javascript |
|
|
|
|
|
|
|
// 错误做法:保存 code 供多次使用 |
|
|
|
|
|
|
|
setOpenId(res.code) // ❌ code 只能用一次 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 正确做法:获取后立即使用 |
|
|
|
|
|
|
|
uni.login({ |
|
|
|
|
|
|
|
success: res => { |
|
|
|
|
|
|
|
// 立即调用登录接口 |
|
|
|
|
|
|
|
this.$store.dispatch('Login', { |
|
|
|
|
|
|
|
type: 34, |
|
|
|
|
|
|
|
code: res.code, // ✅ 立即使用 |
|
|
|
|
|
|
|
state: 'default' |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 处理 code 过期 |
|
|
|
|
|
|
|
```javascript |
|
|
|
|
|
|
|
// 设置 code 有效期检查 |
|
|
|
|
|
|
|
const CODE_EXPIRE_TIME = 4 * 60 * 1000 // 4分钟(保守估计) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 保存 code 时记录时间 |
|
|
|
|
|
|
|
uni.login({ |
|
|
|
|
|
|
|
success: res => { |
|
|
|
|
|
|
|
const codeData = { |
|
|
|
|
|
|
|
code: res.code, |
|
|
|
|
|
|
|
timestamp: Date.now() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
uni.setStorageSync('wxCode', codeData) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 使用时检查是否过期 |
|
|
|
|
|
|
|
const codeData = uni.getStorageSync('wxCode') |
|
|
|
|
|
|
|
if (codeData && (Date.now() - codeData.timestamp < CODE_EXPIRE_TIME)) { |
|
|
|
|
|
|
|
// 使用 code |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// 重新获取 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 优雅的错误提示 |
|
|
|
|
|
|
|
```javascript |
|
|
|
|
|
|
|
const errorMessages = { |
|
|
|
|
|
|
|
'1002018002': '登录信息已过期,正在重新获取...', |
|
|
|
|
|
|
|
'1002018003': '授权无效,请重新进入小程序', |
|
|
|
|
|
|
|
'1002018005': '网络连接失败,请检查网络设置', |
|
|
|
|
|
|
|
'1002018006': '身份验证失败,请重新登录' |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 统一错误处理 |
|
|
|
|
|
|
|
function handleLoginError(error) { |
|
|
|
|
|
|
|
const message = errorMessages[error.code] || error.message || '登录失败' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (error.code === '1002018002') { |
|
|
|
|
|
|
|
// 自动处理,不显示错误 |
|
|
|
|
|
|
|
console.log(message) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// 显示错误提示 |
|
|
|
|
|
|
|
uni.showToast({ |
|
|
|
|
|
|
|
title: message, |
|
|
|
|
|
|
|
icon: 'none', |
|
|
|
|
|
|
|
duration: 2000 |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 后端日志查看 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
当前端遇到登录问题时,可以通过查看后端日志快速定位问题: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. **查看请求日志** |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
[AppLogin][小程序登录开始,code(xxx) type(34) userType(3)] |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. **查看认证过程** |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
[getAuthUser][开始请求社交平台,type(34) userType(2) code(xxx)] |
|
|
|
|
|
|
|
[miniAppLogin][获取到用户信息,openId(xxx) nickname(xxx)] |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3. **查看错误日志** |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
[getAuthUser][社交授权失败,type(34) code(xxx) errorMsg(invalid code)] |
|
|
|
|
|
|
|
[AppLogin][小程序登录失败,code(xxx) error(微信授权码无效或已被使用)] |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
通过这些日志可以快速判断: |
|
|
|
|
|
|
|
- code 是否正确传递 |
|
|
|
|
|
|
|
- 微信接口返回的具体错误 |
|
|
|
|
|
|
|
- 用户是新用户还是老用户 |
|
|
|
|
|
|
|
- 绑定过程是否成功 |
|
|
|