fastapi学习记录【八】

代码地址:GitHub - wendingming/fastapi-vue-postgresql: fastapi+vue+postgresql搭建项目

昨天经过实测,发现http.js的响应拦截存在问题,

昨天的代码:

//响应拦截
http.interceptors.response.use(res => {
    //这里是错误的,res的响应status,不是在成功响应判断,而应该在失败响应里面判断
    const code = res.data.status_code || 200;
    const msg = errorCode[code] || res.data.detail || errorCode['default']
    if (code === 401) {
        ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
            confirmButtonText: '重新登录',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            store.dispatch('loginOut').then(() => {
                location.href = '/index';
            })
        })
    } else if (code === 500) {
        ElMessage.error(msg)
        return Promise.reject(new Error(msg))
    } else if (code !== 200) {
        ElMessage.error(msg)
        return Promise.reject('error')
    } else {
        return res.data
    }
}, err => {
    return Promise.reject(err)
})

修改后的代码:


//响应拦截
http.interceptors.response.use(res => {
    //const code = res.data.status_code || 200;
    //const msg = errorCode[code] || res.data.detail || errorCode['default']
    //console.log(res);
    return res.data
}, err => {
    //console.log(err);
    const code = err.response.status;//注意:状态码是err.response.status,而不是err.status
    const msg = errorCode[code] || errorCode['default'];
    if(code == 401){
        ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
            confirmButtonText: '重新登录',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            store.dispatch('loginOut').then(() => {
                location.href = '/login';
            })
        })
    } else if (code === 500) {
        ElMessage.error("错误500:" + msg)
    } else if (code !== 200) {
        ElMessage.error("错误:" + msg)
    } else {
        return err
    }
    return err
})

总结:错误码不是在响应成功里面拦截,而是在响应失败里面拦截

继续学习,

因为fastapi返回的数据中,中文是转换成unicode代码发送给接口的,于是在前端要解码unicode改成中文,

继续改进成功响应拦截,增加unicode转换成中文代码,改进后的代码如下:


//响应拦截
http.interceptors.response.use(res => {
    //const code = res.data.status_code || 200;
    //const msg = errorCode[code] || res.data.detail || errorCode['default']
    let datas = changearray(res.data);
    return datas
}, err => {
    const code = err.response.status;//注意:状态码是err.response.status,而不是err.status
    const msg = errorCode[code] || errorCode['default'];// || err.data.detail || errorCode['default']
    if(err.response.status == 401){
        ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
            confirmButtonText: '重新登录',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            store.dispatch('loginOut').then(() => {
                location.href = '/login';
            })
        })
    } else if (err.response.status === 500) {
        ElMessage.error("错误500:" + msg)
    } else if (err.response.status !== 200) {
        ElMessage.error("错误:" + msg)
    } else {
        console.log('返回err');
        return err
    }
    return err
})

function changearray(arr){
    let item = JSON.stringify(arr);
    let item1 = toChineseStr(item);
    let item2 = JSON.parse(item1);
    return item2;
}

function toChineseStr(str) {//unicode转中文
    if (str == '') {//空字符串
        return '';
    }
    //例如unicode  \\u7cfb  添加了_unicode_,变成 \\u_unicode_7cfb
    //然后split('\\\\u')切分字符串生成数组,\\u_unicode_7cfb就变成了一个字符串元素:_unicode_7cfb
    //然后循环数组,当循环到这个元素时,
    //判断这个元素值含有_unicode_
    //然后把这个元素值_unicode_7cfb里面的_unicode_替换成空
    //取前面4个字符,得到了7cfb,取第四个字符后面的字符
    //把7cfb进行unicode解码,【使用string.fromCharCode( parseInt('7cfb', 16) ) + 第四个字符后面的字符】就转换成了中文
    let  unicodeStr = str;
    let reg=new RegExp('\\\\u','g')//定义要替换的字符串,g表示要全部替换掉
    let chineseStr = '';
    let itemStr = '';
    let itemStr1 = '';
    let itemStr2 = '';
    unicodeStr = unicodeStr.replace(reg,'\\u_unicode_')//执行替换,吧\\u替换成\\u_unicode_
    unicodeStr = unicodeStr.split('\\\\u');//使用split切分数组
    for (let i = 0, iLength = unicodeStr.length; i < iLength; i++) {
        if(unicodeStr[i].indexOf('_unicode_') !=-1){
            itemStr = unicodeStr[i].replace('_unicode_','');
            itemStr1 = itemStr.substring(0,4);
            itemStr2 = itemStr.substring(4);
            chineseStr += String.fromCharCode(parseInt(itemStr1, 16)) + itemStr2;
        }else{
            chineseStr += unicodeStr[i];
        }
    }
    return chineseStr;
}

接下来做,用户登录后,访问用户信息接口显示管理员信息,

后端fastapi代码如下【后端很简洁】:

main.py增加接口:

#新增接口userInfo【管理员信息接口】
@app.get("/userinfo")
async def userinfo(current_user: User = Depends(get_current_active_user)):
    return current_user

login.py相关代码如下:


async def get_current_active_user(current_user: User = Depends(get_current_user)):
    """获取当前用户信息,实际上是作为依赖,注入其他路由以使用。
    :param current_user:
    :return:
    """
    # 如果用户被禁,抛出异常
    if current_user.disabled:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user

async def get_current_user(token: str = Depends(oauth2_scheme)):
    """获取当前用户信息,实际上是一个解密token的过程
    :param token: 携带的token
    :return:
    """
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        # 解密tokens
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        # 从tokens的载荷payload中获取用户名
        username: str = payload.get("sub")
        # 如果没有获取到,抛出异常
        if username is None:
            raise credentials_exception
        token_data = TokenData(username=username)
    except JWTError:
        raise credentials_exception
    # 从数据库查询用户信息
    user = get_user(fake_users_db, username=token_data.username)
    if user is None:
        raise credentials_exception
    return user

# 创建一个加密解密上下文环境(甚至可以不用管这两句话啥意思)
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


def get_user(db, username: str):
    """查询用户
    :param db: 模拟的数据库
    :param username: 用户名
    :return: 返回一个用户的BaseModel(其实就是字典的BaseModel对象,二者可互相转换)
    """
    if username in db:
        user_dict = db[username]
        return UserInDB(**user_dict)
class UserInDB(User):
    hashed_password: str

# 这里定义一个字典,来模拟数据库中的数据
fake_users_db = {
    "johndoe": {
        "uid": "1",
        "username": "johndoe",
        "full_name": "John Doe",
        "avatar": "https://up.enterdesk.com/2021/edpic/c4/9f/09/c49f090757360f843141fe2bab2cfc8f_1.jpg",
        "email": "[email protected]",
        "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",#默认密码secret
        "disabled": False,
        "permisson": json_permisson
    }
}

VUE修改About.vue如下:




然后就获取到管理员信息了,

最后页面展示如下:

fastapi学习记录【八】_第1张图片

已经成功获得fastapi管理员信息接口,

接下来改进:

一、store.js挂载的member.js添加获得管理员信息的方法

二、about.vue调用store的这个方法,获得管理员信息,并显示

member.js代码如下:

import{getToken,setToken,setTokenType,removeToken} from '@/common/token'
//挂载api接口组件
import api from '@/api/api'
//import { createSocket } from '@/common/websocket'

const user = {
    state: {//定义
        token: getToken(),
        tokentype: '',
        uid:'',                 //管理员id
        username: '',           //管理员名
        fullname: '',           //管理员全名
        avatar: '',             //管理员头像
        email:'',               //管理员邮箱
        permisson:[]            //其它备用【例如:权限】
    },
    mutations: {//赋值
        SET_TOKEN: (state, token) => {
            state.token = token
        },
        SET_TOKENTYPE: (state, tokentype) => {
            state.tokentype = tokentype
        },
        SET_UID: (state, uid) => {
            state.uid = uid
        },
        SET_USERNAME: (state, username) => {
            state.username = username
        },
        SET_FULLNAME: (state, fullname) => {
            state.fullname = fullname
        },
        SET_AVATAR: (state, avatar) => {
            state.avatar = avatar
        },
        SET_EMAIL:(state,email)=>{
            state.email = email
        },
        SET_PERMISSON:(state,permisson)=>{
            state.permisson = permisson
        }
    },
    actions: {//响应方法
        GetInfo({ commit, state }) {//获取管理员信息
            return new Promise((resolve, reject) => {
                api.getInfo().then(res => {
                    const user = JSON.parse(JSON.stringify(res));               //绑定管理员信息到常量
                    const avatar = user.avatar == null ? require("@/assets/img/empty-face.png") : user.avatar;//解析头像地址,没有头像则绑定一张默认头像
                    commit('SET_USERNAME', user.username)          //绑定姓名
                    commit('SET_AVATAR', avatar)                  //绑定头像
                    commit('SET_UID',user.uid);                     //绑定id
                    commit('SET_EMAIL',user.email);           //绑定email
                    commit('SET_PERMISSON',user.permisson);       //绑定权限
                    resolve(state)
                }).catch(error => {
                    reject(error)
                })
            })
        },
        Login({commit},userInfo){//访问登录接口
            console.log('开始登录');
            return new Promise((resolve,reject)=>{
                api.login(userInfo).then(res=>{
                    console.log(res);
                    setToken(res.access_token);
                    setTokenType(res.token_type);
                    commit('SET_TOKEN',res.access_token)
                    commit('SET_TOKENTYPE',res.token_type)
                    resolve()
                }).catch(error=>{
                    reject(error)
                })
            })
        },
        loginOut({ commit, state }) {//退出登录
            return new Promise((resolve, reject) => {
                console.log(state);
                console.log(reject);
                commit('SET_TOKEN', '');
                commit('SET_TOKENTYPE','')
                commit('SET_UID','');
                commit('SET_USERNAME','');
                commit('SET_FULLNAME','');
                commit('SET_AVATAR','');
                commit('SET_EMAIL','');
                commit('SET_ACCOUNT','');
                commit('SET_PERMISSON',[]);
                removeToken();
                resolve();
            })
        },
    }
}
export default user

 about.vue修改如下:




OK,今天就学习到这。

你可能感兴趣的:(fastapi,python,vue.js)