最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】Django+jwt-token-auth的后端和Antd Pro的Reactjs的前端实现用户名密码错误人性化提示

Django crifan 6737浏览 0评论

现有: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

->

Ant Design – 开箱即用的中台前端/设计解决方案

找找错误提示

开始使用 – Ant Design

用户头像列表 AvatarList – Ant Design

ant-design-pro 错误提示

表单 Form – Ant Design

ant-design-pro-site/error.md at master · ant-design/ant-design-pro-site

提示性报错

* Alert

警告提示 Alert – Ant Design

* message

全局提示 Message – Ant Design

* notification

通知提醒框 Notification – Ant Design

-》好像antd pro中此处就是用的notification的error

notification.error(config)

-〉所以去搜索项目代码看看:

notification.error(

果然:

先去:

【已解决】js中如何判断json对象中是否包含某个键key

然后把相关代码改为:

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的前端实现用户名密码错误人性化提示

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
89 queries in 0.204 seconds, using 22.16MB memory