现有:Django的后端,密码验证是利用jwt-token-auth实现的token的形式
前端是Reactjs的AntD的项目,基于
https://github.com/ant-design/ant-design-pro
改动而来。
现在有个问题:
当用户名或密码错误是,web前端显示的是:
而不是我们希望的:
提示我们用户名或密码出错
最好是提示更准确的原因,比如用户名不存在,密码错误
经过研究代码,找到了对应的最近的位置:
/xxx/src/models/login.js
effects: {
*login({ payload }, { call, put }) {
console.log("login: payload=", payload)
const response = yield call(getUserToken, payload);
console.log("response=", response)
response.status = ‘ok’
response.type = ‘account’
response.currentAuthority = ‘user’
yield put({
type: ‘changeLoginStatus’,
payload: response,
});
// Login successfully
if (response.status === ‘ok’) {
reloadAuthorized();
yield put(routerRedux.push(‘/’));
}
},
然后去加上:
response不为空的判断,然后,只能在console中输出提示出错
effects: {
*login({ payload }, { call, put }) {
console.log("login: payload=", payload)
const response = yield call(getUserToken, payload);
console.log("response=", response)
if (response) {
response.status = ‘ok’
response.type = ‘account’
response.currentAuthority = ‘user’
yield put({
type: ‘changeLoginStatus’,
payload: response,
});
// Login successfully
if (response.status === ‘ok’) {
reloadAuthorized();
yield put(routerRedux.push(‘/’));
}
} else {
// alert("用户名或密码错误")
console.error("用户名或密码错误")
}
},
希望还是找到其他更好的,比如在login登录界面中提示出错才好
然后再去找代码的内部调用逻辑
xx/src/services/api.js
export async function getUserToken(params) {
return request(`${apiPrefix}/jwt-token-auth/`, {
method: ‘POST’,
// credentials : ‘include’,
body: params,
});
}
xx/src/utils/request.js
import fetch from ‘dva/fetch’;
import { notification } from ‘antd’;
import { routerRedux } from ‘dva/router’;
import store from ‘../index’;
const codeMessage = {
200: ‘服务器成功返回请求的数据。’,
201: ‘新建或修改数据成功。’,
202: ‘一个请求已经进入后台排队(异步任务)。’,
204: ‘删除数据成功。’,
400: ‘发出的请求有错误,服务器没有进行新建或修改数据的操作。’,
401: ‘用户没有权限(令牌、用户名、密码错误)。’,
403: ‘用户得到授权,但是访问是被禁止的。’,
404: ‘发出的请求针对的是不存在的记录,服务器没有进行操作。’,
406: ‘请求的格式不可得。’,
410: ‘请求的资源被永久删除,且不会再得到的。’,
422: ‘当创建一个对象时,发生一个验证错误。’,
500: ‘服务器发生错误,请检查服务器。’,
502: ‘网关错误。’,
503: ‘服务不可用,服务器暂时过载或维护。’,
504: ‘网关超时。’,
};
function checkStatus(response) {
console.log(`checkStatus: response=`, response)
console.log(`response.body=`, response.body)
if (response.status >= 200 && response.status < 300) {
return response;
}
const errortext = codeMessage[response.status] || response.statusText;
notification.error({
message: `请求错误 ${response.status}: ${response.url}`,
description: errortext,
});
const error = new Error(errortext);
error.name = response.status;
error.response = response;
// throw error;
}
/**
* Requests a URL, returning a promise.
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
* @return {object} An object containing either "data" or "err"
*/
export default function request(url, options) {
const defaultOptions = {
credentials: ‘include’,
};
const newOptions = { …defaultOptions, …options };
if (newOptions.method === ‘POST’ || newOptions.method === ‘PUT’ || newOptions.method === ‘PATCH’) {
if (!(newOptions.body instanceof FormData)) {
newOptions.headers = {
Accept: ‘application/json’,
‘Content-Type’: ‘application/json; charset=utf-8’,
…newOptions.headers,
};
newOptions.body = JSON.stringify(newOptions.body);
} else {
// newOptions.body is FormData
newOptions.headers = {
Accept: ‘application/json’,
…newOptions.headers,
};
}
}
return fetch(url, newOptions)
.then(checkStatus)
.then(response => {
if (newOptions.method === ‘DELETE’ || response.status === 204) {
return response.text();
}
if (url.includes(‘word’)) {
window.open(url);
}
return response.json();
})
.catch(e => {
console.log(`url=${url} -> error=`, e);
const { dispatch } = store;
const status = e.name;
if (status === 401) {
dispatch({
type: ‘login/logout’,
});
return;
}
if (status === 403) {
dispatch(routerRedux.push(‘/exception/403’));
return;
}
if (status <= 504 && status >= 500) {
dispatch(routerRedux.push(‘/exception/500’));
return;
}
if (status >= 404 && status < 422) {
dispatch(routerRedux.push(‘/exception/404’));
}
});
}
发现此处request(内部是用到了fetch)
并没有给外部api调用时,提供callback
而是全局去判断了http的status code
即在checkStatus中统一处理response后error
而Django后端中,找到登录所对应代码是:
/NaturlingCmsServer/NaturlingCmsServer/urls.py
url(r’^api/v1/jwt-token-auth/’, obtain_jwt_token, name=’token-auth’),
url(r’^api/v1/jwt-token-refresh/’, refresh_jwt_token, name=’token-refresh’),
然后并没有找到obtain_jwt_token在哪里实现的
【已解决】Django中如何自定义JWT获取token失败时返回的错误信息
接下来,就是要去搞清楚:
如何以用户能接受和看得清的方式,显示和告诉用户:
用户名或密码出错了
要么是:覆盖,重写
当jwt获取token出错的时候,此处的错误提示弹框:
要么是:
登录界面上找个地方,显示错误信息
要么是:
一闪而过的错误提示信息
去找找,此处的Reactjs的Antd中,到底哪个更方便实现
https://github.com/ant-design/ant-design-pro
->
找找错误提示
用户头像列表 AvatarList – Ant Design
ant-design-pro 错误提示
ant-design-pro-site/error.md at master · ant-design/ant-design-pro-site
提示性报错
* Alert
* message
* notification
通知提醒框 Notification – Ant Design
-》好像antd pro中此处就是用的notification的error
notification.error(config)
-〉所以去搜索项目代码看看:
notification.error(
果然:
先去:
然后把相关代码改为:
function checkStatus(response) {
console.log(`checkStatus: response=`, response)
console.log(`response.body=`, response.body)
if (response.status >= 200 && response.status < 300) {
return response;
}
response.json().then(
respBody => {
console.log(`debugResponse`)
console.log(`typeof respBody=`, typeof respBody)
console.log(`respBody=`, respBody)
console.log("JSON.stringify(respBody)=",JSON.stringify(respBody))
let respMessage
if ("message" in respBody) {
respMessage = respBody.message
console.log(`respMessage=`, respMessage)
} else {
console.log("message not in response body")
}
// const errortext = codeMessage[response.status] || response.statusText;
const errortext = respMessage || codeMessage[response.status] || response.statusText;
console.log("response.status=", response.status)
console.log("response.url=", response.url)
console.log("errortext=", errortext)
notification.error({
// message: `请求错误 ${response.status}: ${response.url}`,
// description: errortext,
message: errortext,
description: `请求 ${response.url} 出错 ${response.status}`,
});
const error = new Error(errortext);
error.name = response.status;
error.response = response;
// throw error;
}
)
// // const errortext = codeMessage[response.status] || response.statusText;
// const errortext = respMessage || codeMessage[response.status] || response.statusText;
// console.log("response.status=", response.status)
// console.log("response.url=", response.url)
// console.log("errortext=", errortext)
// notification.error({
// message: `请求错误 ${response.status}: ${response.url}`,
// description: errortext,
// });
// const error = new Error(errortext);
// error.name = response.status;
// error.response = response;
// // throw error;
}
效果:
不过关于错误处理,回头好好看看这个:
如何处理 status 等于 400 的情况? · Issue #959 · ant-design/ant-design-pro
或许有所帮助
【总结】
此处,先去通过:
【已解决】Django中如何自定义JWT获取token失败时返回的错误信息
给Django的JWT的token获取出错时,返回自定义的错误信息,其中包含message
然后再去Antd Pro中reactjs中的fetch中,对于response的body中,把ReadableStream转换为json,拿到message,然后调用antd的notification.error去显示出错信息:
使得用户在输入了用户名或密码出错时,能知道是用户名或密码出错了。
而不是之前的400提示,用户完全不知道什么原因。
转载请注明:在路上 » 【已解决】Django+jwt-token-auth的后端和Antd Pro的Reactjs的前端实现用户名密码错误人性化提示