AntD的前端设计(二)
之前只讲如何配置 RequestConfig 和 ResponseStructure, 这里面内部其实就是为了保持和服务端消息同步,
日常消息协议格式我都采取以下方式:
// 常规消息结构体
{
"error": 0,
"message": "success",
"data": {},
}
// 这里提供登录授权完成和数据分页完成格式的返回示例
// 1. 授权完成
{
"error": 0,
"message": "success",
"data": {
"uid": 1,
"username": "meteorcat",
"nickname": "MeteorCat",
"token": "97ba4dd71592c7b26bc90308806d42f3"
},
}
// 2. 分页返回, 分页返回有两种:
// 2.1 前端推送页数(page)和数据量(total), 服务端返回当前页和总页数(list,page,total)
// 2.2 前端推送偏移两(offset)和数据量(total), 服务端返回当前页和总页数(list,page,total)
{
"error": 0,
"message": "success",
"data": {
"list": [
{
"id": 1,
"name": "MeteorCat"
},
// 其他数据
],
"page": 1,
// 数据分页页码
"total": 10,
// 总共数据页数
}
}
大部分业务都是围绕数据流展示( 像是支付订单|人员流失的查询 )和图表分析( 后台返回数据JSON格式 ), 基本上面那些方式够用了.
这里先编写 mock 测试数据用于之前编写的授权接口( mock/authAPI.ts ):
// mock 首先定义用户登录数据, 需要创建优先的 authAPI 接口
// 路径: mock/authAPI.ts
export default {
// 登录接口
// 定义数据格式 { error:int, message:string, data:any }
'POST /api/auth/login': (req: any, res: any) => {
// 这里模拟登录接口指定账号
const data = req.body || {};
const username = data.username || "";
const password = data.password || "";
// 测试账号
if (username !== "meteorcat") {
res.json({
error: 1,
message: "找不到账号",
data: {},
})
return;
}
// 测试密码
if (password !== "meteorcat") {
res.json({
error: 1,
message: "密码错误",
data: {},
})
return;
}
// 通过验证直接返回
res.json({
error: 0,
message: "success",
data: {
uid: 1,
username: "MeteorCat",
nickname: "meteorcat",
token: "97ba4dd71592c7b26bc90308806d42f3"
}
});
},
// 登出接口
'/api/auth/logout': (req: any, res: any) => {
// 需要识别 JWT 授权是否存在
const headers = req.headers || {}
const auth = headers.authorization || "";
// 确认授权
if (auth.length <= 0) {
res.json({
error: 1,
message: "未授权操作",
data: {}
});
return;
}
// 对比 JWT 授权
if (auth !== 'Bearer 97ba4dd71592c7b26bc90308806d42f3') {
res.json({
error: 1,
message: "未授权操作",
data: {}
});
return;
}
res.json({
error: 0,
message: "success",
data: {}
});
}
}
这里启动项目之后, 默认就会挂起个 Web 服务监听服务( 默认访问 http://localhost:8000 ), 按照上面编写的接口可以请求到:
- http://localhost:8000/api/auth/login : 需要
POST + RAW提交 JSON 参数(username,password) - http://localhost:8000/api/auth/logout : 需要
Header内部带有 JWT 请求参数
可以试着推送测试数据确定是否能够跑通, 如果跑通之后就可以准备去测试联调之前的页面功能.
网络请求
umi 内部已经集成了网络请求接口, 内部已经集成好对象:
//import {request, useRequest} from 'umi';
import {request} from "@umijs/max"; // max 框架
request;
// 样例: request<ResponseAuthLogin>('url',{})
useRequest;
// 样例: const { data, error, loading } = useRequest(service);
所以基本上只需要调用请求即可, 一般网络请求都是在 src/services 内部文档处理;
官方内部放置了 demo 样例引入 OneAPI 自动生成, 这里只需要定义响应工具原型就能编写:
// 文件路径: src/utils/request.ts
// 后续请求工具类在此编写
// 响应格式化对象
export interface ResponseBody<T> {
error: number,
message: string,
data: T
}
之后可以编写具体的请求业务对象服务:
// 文件路径: src/services/auth.ts
import {request} from "@umijs/max";
import {ResponseBody} from "@/utils/request";
// 响应格式化 - 具体数据
interface ResponseAuthLoginData {
uid: number,
username: string,
nickname: string,
token: string,
}
// 登录接口
export async function login(
username: string,
password: string,
options?: { [key: string]: any },
) {
return request<ResponseBody<ResponseAuthLoginData>>('/api/auth/login', {
method: 'POST',
data: {
username: username,
password: password,
},
...(options || {}),
});
}
// 登出接口
export async function logout(
options?: { [key: string]: any },
) {
return request<ResponseBody<any>>('/api/auth/logout', {
method: 'GET',
...(options || {}),
});
}
最后跑下页面请求代码, 我试用过官方提供的 useRequest, 后续感觉功能实际有点冗余不如直接编写请求高效快捷点, 原来的页面文件编写如下
// 文件路径: src/pages/Auth/Login/index.tsx
export default () => {
const {token} = theme.useToken();
const {setUsername, setNickname, setUid, setToken} = useModel('global');
return (
<ProConfigProvider hashed={false}>
<div style={{backgroundColor: token.colorBgContainer}}>
<LoginForm
title="Github"
subTitle="全球最大的代码托管平台"
onFinish={async (values) => {
const result = await login(values.username || '', values.password || '');
// 确定是否登录完成
if (result.error === 0) {
// 写入全局授权
const data = result.data;
setUid(data.uid);
setNickname(data.nickname);
setUsername(data.username);
setToken(data.token);
// 跳转首页
history.push("/home");
}
}}
>
</LoginForm>
</div>
</ProConfigProvider>
)
}
这里测试之后能够正式跳转, 后续就是准备授权拦截的功能编写了.