Da-API平台-接口发布、在线调用
模块开发
1.接口发布下线
【1】接口管理(发布、下线)
概念设计
(1)流程设计
基于现有接口管理模块开发一个用于发布和下线接口的功能。本质上来说,就是改变每条接口数据的状态。在设计接口信息表时,之前已经预留了一个状态字段status。其中,关闭和开启分别对应接口的下线和上线。只有状态为 1 的接口才可以被用户调用,否则将无法调用。(优先后台接口开发,后续完善页面设计)
(2)功能设计
开发发布接口和下线接口(仅管理员可操作这两个接口,防止用户越权操作)。大致规划一下思路:
发布接口:这个接口需要执行哪些任务呢?首先需要验证接口是否存在,然后判断接口是否可调用,否则访问接口都是 404,影响用户体验。如果接口可以调用,需要修改数据库中该接口的状态为 1,表示接口已经被发布,状态默认为 0(关闭)。
下线接口:可以为其新增一个状态字段。例如,使用 1 表示开启,使用 2 表示下线。通过这个新字段,可以清晰地区分接口状态。当状态为 0 时,表示该接口还没有进行任何处理,看大家自己的考虑。我们这里就直接使用 0 和 1 来表示状态,不再添加额外的状态字段,可以按照自己的需求进行设计。对于下线接口,校验接口是否存在也是和发布接口类似的,但是下线接口无需判断接口是否可调用。
所有的业务和系统都是灵活的,目前这个 API 接口开放平台只是一个简单的标准而已,具体的业务细节还是需要根据实际情况来进行调整。
接口开发
后端接口开发
首先先梳理基本的接口发布、上线流程,然后再完善细节
首先获取当前登录用户的信息,然后判断用户是否具有管理员权限。如果没有权限,就会直接抛出权限异常;如果有权限,就会继续执行后续操作。这种方式被称为 AOP 切面的基本应用之一,AOP常见应用场景:日志记录、接口鉴权、数据校验等
判断发布接口是否可以调用(API鉴权),可以借助api-platform-client-sdk进行操作,此处引入该依赖,并配置ak、sk
pom.xml配置
<!-- 引入自定义api-client-sdk -->
<dependency>
<groupId>com.noob</groupId>
<artifactId>api-platform-client-sdk</artifactId>
<version>0.0.1</version>
</dependency>
application.yml配置
# api-platform-client-sdk配置
noob:
client:
access-key: noob
secret-key: abcdefg
controller提供接口,完成发布、下线功能(此处IdRequest是请求参数定义,因为接口状态变更需要id参数,为了统一规范,此处加入IdRequest定义)
/**
* 接口信息
*/
@RestController
@RequestMapping("/interfaceInfo")
@Slf4j
public class InterfaceInfoController {
@Resource
private ApiClient apiClient;
/**
* 发布接口:
* 1.校验接口是否存在
* 2.判断接口是否可以被调用
* 3.修改数据库中接口信息状态为1
* @param idRequest
* @param request
* @return
*/
@PostMapping("/online")
@AuthCheck(mustRole = "admin")
public BaseResponse<Boolean> onlineInterfaceInfo(@RequestBody IdRequest idRequest,
HttpServletRequest request) {
if (idRequest == null || idRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
// 1.校验该接口是否存在
long id = idRequest.getId();
InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
if (oldInterfaceInfo == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
}
// 2.判断该接口是否可以调用
// 创建一个User对象(模拟数据)
com.noob.apiclientsdk.model.User user = new com.noob.apiclientsdk.model.User();
// 设置user对象的username属性为"test"
user.setUsername("test");
// 通过apiClient的getUsernameByPost方法传入user对象,并将返回的username赋值给username变量
String username = apiClient.getUserNameByPostBySign(user);
// 如果username为空或空白字符串
if (StringUtils.isBlank(username)) {
// 抛出系统错误的业务异常,表示系统内部异常,并附带错误信息"接口验证失败"
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "接口验证失败");
}
// 3.修改接口数据库中的状态字段为 1
// 创建一个InterfaceInfo对象
InterfaceInfo interfaceInfo = new InterfaceInfo();
// 设置interfaceInfo的id属性为id
interfaceInfo.setId(id);
interfaceInfo.setStatus(InterfaceInfoEnum.ONLINE.getValue());
boolean result = interfaceInfoService.updateById(interfaceInfo);
// 4.返回响应数据
return ResultUtils.success(result);
}
/**
* 下线接口:
* 1.校验接口是否存在
* 2.修改数据库中接口信息状态为1
* @param idRequest
* @param request
* @return
*/
@PostMapping("/offline")
@AuthCheck(mustRole = "admin")
public BaseResponse<Boolean> offlineInterfaceInfo(@RequestBody IdRequest idRequest,
HttpServletRequest request) {
if (idRequest == null || idRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
// 1.校验该接口是否存在
long id = idRequest.getId();
InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
if (oldInterfaceInfo == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
}
// 2.修改接口数据库中的状态字段为 1
InterfaceInfo interfaceInfo = new InterfaceInfo();
interfaceInfo.setId(id);
interfaceInfo.setStatus(InterfaceInfoEnum.OFFLINE.getValue());
boolean result = interfaceInfoService.updateById(interfaceInfo);
// 返回响应数据
return ResultUtils.success(result);
}
}
接口测试,启动项目(并启动api-platform-interface接口进行访问测试):测试发布、下线接口,其中发布接口需要调用api-platform-interface接口,因此要注意检查api-platform-interface项目是否正常启动再进行测试
前端开发
调整前端目录结构,pages/新建Admin文件夹,随后将InterfaceInfo文件夹放入其中,并修改routes(调整路由引入的组件路径,规范开发)
{ name: '接口信息管理', icon: 'table', path: 'admin/interce_info', component: './Admin/InterfaceInfo' }
在接口信息管理操作区中增加发布、下线按钮(调用后台响应接口进行测试):前端开发核心在于:页面定义、接口调用
【1】定义按钮(参考删除按钮,点击触发时间)
【2】实现按钮交互(点击触发相应的handleXXX处理方法)
【3】响应后台接口交互并处理(引入后台接口yarn run openapi
实现更新api,调用后台请求)
# 参考代码实现
// 1.执行yarn run openapi更新后台数据接口
(执行该指令可以看到其会在原来接口基础上补充了offlineInterfaceInfoUsingPost、onlineInterfaceInfoUsingPost),前端直接调用即可
// 2.封装按钮功能组件,并实现后台响应交互
// 2.1 引入后台接口(发布、下线)
import { onlineInterfaceInfoUsingPost,offlineInterfaceInfoUsingPost} from '@/services/api-platform-backend/interfaceInfoController';
// 2.2 定义功能组件(仿照删除按钮实现,点击触发根据id进行状态修改)
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
.......... 修改组件定义 ..........
<a key="config"
onClick={()=>{
handleOnline(record);
}}>
上线
</a>,
<a key="config"
onClick={()=>{
handleOffline(record);
}}>
下线
</a>,
.......... 其他组件定义 ..........
],
},
// 2.3 分别实现按钮点击触发的功能(发布handleOnline、下线handleOffline)
const handleOnline = async (record: API.InterfaceInfo) => {
// 设置加载中的提示为'正在处理'
const hide = message.loading('正在处理');
if (!record) return true;
try {
// 调用接口
await onlineInterfaceInfoUsingPost({
id: record.id
});
hide();
// 如果调用成功会提示'处理成功'
message.success('处理成功');
// 处理成功自动刷新表单
actionRef.current?.reload();
return true;
} catch (error: any) {
hide();
// 否则提示'处理成功' + 报错信息
message.error('处理成功,' + error.message);
return false;
}
};
const handleOffline = async (record: API.InterfaceInfo) => {
// 设置加载中的提示为'正在处理'
const hide = message.loading('正在处理');
if (!record) return true;
try {
// 调用接口
await offlineInterfaceInfoUsingPost({
id: record.id
});
hide();
// 如果调用成功会提示'处理成功'
message.success('处理成功');
// 处理成功自动刷新表单
actionRef.current?.reload();
return true;
} catch (error: any) {
hide();
// 否则提示'处理成功' + 报错信息
message.error('处理成功,' + error.message);
return false;
}
};
此处校验的时候需要注意的是,发布接口的时候要检查接口调用的可用性,因此此处后台启动相应要有api-platform-interface的启动,以确api-platform-backend在调用请求校验的时候保持正常校验操作,否则网络无法调通则会抛出异常错误
优化点:上面操作实现了接口发布、下线的基本功能,但是实际业务需求场景不会说同时出现上线/下线两个按钮控制,因此此处要进行按钮状态控制,当接口处于下线状态的时候提供发布按钮、当接口处于发布状态的时候提供下线按钮。
【1】设置不同的key属性
发布和下线的按钮都有 key 属性,默认是 config,设置成不一样的即可,原因是,在 React 中,如果列表中的元素需要进行增删操作,需要为每个元素指定唯一的 key。这是因为React 使用 key 来识别列表中的每个元素,以便在更新列表时能够准确地判断新旧元素的对应关系,从而提高渲染性能。 给发布按钮和下线按钮设置不同的 key 是解决重复渲染问题的一种方法。通过设置不同的 key 值,React 在进行新旧对比时会识别出这是两个不同的元素,从而确保它们能够正确地渲染和更新。所以,可以通过给发布按钮和下线按钮设置不同的 key 值来解决按钮重复渲染的问题,确保 React 能够正确地进行虚拟 DOM 的对比和更新。
【2】根据条件渲染逻辑(回归本质,即根据状态渲染按钮:状态为发布则渲染下线按钮、状态为下线则渲染发布按钮、其他状态不作任何处理)
【2】浏览页开发
功能说明:创建一个给用户看的页面
前端开发
(1)浏览列表页面开发
可以适当清理一些不需要用到的页面,例如Amin.tsx、Welcome.tsx等,自己创建自己需要的功能页面
此处pages下创建Index目录,复制Welcome.tsx到该目录(修改为index.tsx),route.tsx相应引入浏览主页路由
启动项目访问测试,看页面是否正常加载,如果正常加载可进入下一步页面修改操作(修改Index/index.tsx为主页内容即可)
上述index.tsx是基于Welcome.tsx的内容,所以需要清理掉一些无用的信息,只需要保留最重要的框架结构即可
import { PageContainer } from '@ant-design/pro-components';
import React from 'react';
const Index: React.FC = () => {
return (
<PageContainer>
</PageContainer>
);
};
export default Index;
可以从ant design组件库查阅组件用法,随后直接基于基础组件构建自己想要的页面即可
import { PageContainer } from '@ant-design/pro-components';
import React, { useEffect, useState } from 'react';
import { List, message } from 'antd';
import { listInterfaceInfoByPageUsingPost } from '@/services/api-platform-backend/interfaceInfoController';
/**
* 主页
* @constructor
*/
const Index: React.FC = () => {
const [loading, setLoading] = useState(false);
const [list, setList] = useState<API.InterfaceInfo[]>([]);
const [total, setTotal] = useState<number>(0);
const loadData = async (current = 1, pageSize = 5) => {
setLoading(true);
try {
const res = await listInterfaceInfoByPageUsingPost({
current,
pageSize,
});
setList(res?.data?.records ?? []);
setTotal(res?.data?.total ?? 0);
} catch (error: any) {
message.error('请求失败,' + error.message);
}
setLoading(false);
};
useEffect(() => {
loadData();
}, []);
return (
<PageContainer title="在线接口开放平台">
<List
className="my-list"
loading={loading}
itemLayout="horizontal"
dataSource={list}
renderItem={(item) => {
const apiLink = `/interface_info/${item.id}`;
return (
<List.Item actions={[<a key={item.id} href={apiLink}>查看</a>]}>
<List.Item.Meta
title={<a href={apiLink}>{item.name}</a>}
description={item.description}
/>
</List.Item>
);
}}
pagination={{
// eslint-disable-next-line @typescript-eslint/no-shadow
showTotal(total: number) {
return '总数:' + total;
},
pageSize: 5,
total,
onChange(page, pageSize) {
loadData(page, pageSize);
},
}}
/>
</PageContainer>
);
};
export default Index;
需要注意的是修改后的index.tsx中有两个将页数设置为数字 5 的设置,也就是多次使用重复的数字。这里需要记住的是,当在代码中使用魔法值(即凭空出现的数值)时,如果发现需要在多个地方修改这个数值,建议将其提取为一个常量。为什么要提取为常量呢?因为使用常量可以提高代码的可维护性和可读性。通过将魔法值提取为常量,然后就可以修改常量的值来一次性修改多处使用该值的地方,而不必逐个搜索和修改每个出现的地方。
(2)查看详情信息开发
去 route.ts 添加路由,动态路由可以查看官网 —— UmiJS,给这个路由新增两个参数:
让这个路由可以接收动态参数,在点击查看之后可以跳到对应的接口页面,通过 id 来区分不同的接口。
path: '/interface_info/:id':定义了路由的路径,其中
:id
是一个参数占位符,表示在实际路径中可以传递一个具体的ID值作为参数。让这个页面在菜单栏中隐藏,查看接口不需要放在菜单栏上。
hideInMenu: true:表示该路由在菜单中是否隐藏,如果设置为 true,则该路由不会在菜单中显示。
配置路由:先创建pages/InterfaceInfo/index.tsx文件,随后在routers.tsx中配置路由
修改InterfaceInfo/index.tsx文件,实现动态路由,展示最基础的页面信息显示,随后再进一步美化页面
import { PageContainer } from '@ant-design/pro-components';
import React, { useEffect, useState } from 'react';
import { useMatch } from 'react-router';
/**
* 查看接口信息详情
* @constructor
*/
const Index: React.FC = () => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<API.InterfaceInfo>();
// 使用useMatch钩子将当前URL与指定的路径模式/interface_info/:id进行匹配,
// 并将匹配结果赋值给match变量
const match = useMatch('/interface_info/:id');
// 使用JSON.stringify将match变量的值转换为JSON字符串,并通过alert函数进行弹窗显示
alert(JSON.stringify(match));
const loadData = async () => {
};
useEffect(() => {
loadData();
}, []);
return (
<PageContainer title="查看接口文档">
</PageContainer>
);
};
export default Index;
之前的 userMatch 可以获取整个页面路径的详细信息,但只需要拿动态路由的参数。这里官网还提供了一个叫做 useParams 的钩子函数,通过使用 useParams,可以轻松地获取动态路由中的参数值,而无需关心整个页面路径的其他细节。继续修改查看接口文档页面,测试功能实现。访问链接:http://localhost:8000/interface_info/2,可以根据id查看指定页面并获取到数据信息
import { getInterfaceInfoVoByIdUsingGet } from '@/services/api-platform-backend/interfaceInfoController';
import { PageContainer } from '@ant-design/pro-components';
import { message } from 'antd';
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router';
/**
* 主页
* @constructor
*/
const Index: React.FC = () => {
// 定义状态和钩子函数
const [loading, setLoading] = useState(false);
const [data, setData] = useState<API.InterfaceInfo>();
// 使用 useParams 钩子函数获取动态路由参数
const params = useParams();
const loadData = async () => {
// 检查动态路由参数是否存在
if (!params.id) {
message.error('参数不存在');
return;
}
setLoading(true);
try {
// 发起请求获取接口信息,接受一个包含 id 参数的对象作为参数
const res = await getInterfaceInfoVoByIdUsingGet({
id: Number(params.id),
});
// 将获取到的接口信息设置到 data 状态中
setData(res.data);
} catch (error: any) {
// 请求失败处理
message.error('请求失败,' + error.message);
}
// 请求完成,设置 loading 状态为 false,表示请求结束,可以停止加载状态的显示
setLoading(false);
};
useEffect(() => {
loadData();
}, []);
return (
<PageContainer title="查看接口文档">
{
// 将 data 对象转换为 JSON 字符串
JSON.stringify(data)
}
</PageContainer>
);
};
export default Index;
进一步美化页面:参考ant design组件,选择合适的组件完善页面信息,类似描述列表组件等,参考官网实现,复制代码即可
完成上述操作,查看接口信息,后续可提供一个在线调用的接口供用户测试
2.在线调用
【1】后端申请签名
注册逻辑修改(补充ak、sk自动绑定)
后端申请签名,可以额外提供接口、页面供用户进行接口申请,也可以用户注册逻辑中直接自动生成相应的accessKey、secretKey,绑定到该用户中
PS:原数据库设计用户没有AK、SK字段需要相应补充进去,修改数据表结构(建议尽量补充字段,不要影响原有的业务逻辑导致其它问题出错)和相关的User、UserMapper.xml、UserServiceImpl.java实现
完成修改后清理数据库数据,重新调用注册接口验证数据是否正常插入、ak/sk是否正常分配即可
随后模拟真实数据进行操作(可以从一些真实请求的接口里面获取参数,插入数据库中模拟),查看前后端请求响应的效果
PS:将Admin/index.tsx中请求参数、请求头、响应参数、响应头等的valueType由原来的textarea修改为jsonCode(展示json格式数据)
可优化点
针对requestParams、responseParams、请求头、响应头等信息,可以考虑在表单的设计上下功夫。可以将表单改造成每个请求参数单独一行让用户输入,每个请求头也单独一行,然后将这个 JavaScript 对象转换为 JSON 格式,再传递给后台,这样就不会出现换行符等问题了,这有点类似于之前提到的 SQLFather 项目中的表单设计。通过这种方式,能够更清晰地管理请求参数和请求头,确保它们的准确性和一致性。(例如前端处理json格式转化,后端用String接收转化要注意一些细节问题,前端处理的时候也要提供一些便捷测试接口的入口,例如参考swagger的接口文档,提供一个灵活的在线调试的入口)
前端代码构建梳理:在查看接口信息详情中,引入表单项用于接口在线调用测试(初稿参考设计页面如下所示)
# 在InterfaceInfo/index.tsx文件中添加Card组件,完成按钮事件触发定义
<Card>
{/* 创建一个表单,表单名称为"invoke",布局方式为垂直布局,当表单提交时调用onFinish方法 */}
<Form name="invoke" layout="vertical" onFinish={onFinish}>
{/* 创建一个表单项,用于输入请求参数,表单项名称为"userRequestParams" */}
<Form.Item label="请求参数" name="userRequestParams">
<Input.TextArea />
</Form.Item>
{/* 创建一个包裹项,设置其宽度占据 16 个栅格列 */}
<Form.Item wrapperCol={{ span: 16 }}>
{/* 创建调用按钮*/}
<Button type="primary" htmlType="submit">
调用
</Button>
</Form.Item>
</Form>
</Card>
// 在线调试表单测试
const onFinish = (values: any) => {
alert('请求调用测试');
console.log('Success:', values);
};
调用流程分析
接下来要实际地让后端去调用这个接口,因此要开发一个在线调用的后端:
如何在后端处理这个在线调用的问题。首先,要考虑的是用户的请求是不固定的,每个接口的请求参数和请求头可能都不同。现在的问题是应该如何将这些请求传递给真实的第三方接口呢?
目前有三个项目:前端项目(刚刚写的点击调用)、接口平台的后端项目(api-backend)、以及提供给开发者的模拟接口项目(api-interface)。那么现在的问题是,前端点击调用后,是直接请求接口平台后端,再由后端调用模拟接口;还是前端绕过后端,直接调用模拟接口呢?
思考一下这两种方案的优缺点。在设计方案时,不应该固定地认为某种方案是最好的,而是要思考每种方案的优点和缺点,然后选择最适合的方案。
实际上,在企业项目中,选择第二种方式是不太可能的。原因在于,如果模拟接口可以直接被调用,那么存在安全风险。通常情况下,前端虽然可以直接调用模拟接口,但不会将模拟接口暴露给外部,而是将其隐藏起来。用户或开发者在调用时可能根本不知道模拟接口的地址。假设,模拟接口的地址是 aaa.com/api,后端地址是 bbb.com/api,而 aaa.com/api 并不对用户开放,用户根本不知道它的存在。 为了更规范、更安全,以及方便进行统计,建议使用后端调用的方式。这种方式更加规范和安全,还可以隐藏接口地址。如果直接将模拟接口完全开放给用户,那么后续的网关和计费等工作可能会徒劳无功。因为对方可以直接请求到你的模拟接口。当然,你可能还需要为模拟接口提供一些特殊保障,所以推荐使用第一种方式。
如果是本人测试自己提交的接口是不是第二种也可以?
当然,第二种方式并不是完全行不通的。它的优点在于简单直接,但是使用第二种方式的前提是你必须确保它的安全性。只要你能确保安全性,比如项目只是你个人使用,那么直接使用第二种方式肯定更加方便,所以要根据具体情况来决定选择哪种方式。
此处实现的是第一种方式,即前端在调用接口时,首先将要调用的接口以及请求参数传递给后端,然后后端作为一个中转角色,再向模拟接口发送请求。除了中转功能,后端可能还需要进行一些判断,例如判断前端的测试频率是否过高,或者判断前端是否有权限进行该接口的测试。因此,使用后端作为中转会更加方便。因此,此处选择第一种方式实现。前端要做的事情,就是把所有它要调用的接口 id 、请求参数传给后端,后端负责调用。
【2】开发在线调用
调用流程
- 前端将用户输入的请求参数和要测试的接口 id 发给平台后端
- 后台接收前端请求后对调用接口进行校验(包括请求调用次数等)
- 检验通过之后由平台后端去调用模拟接口后响应数据返回给前端
(初步流程构建可以先采用一些简单的接口设计进行测试,例如可以借助前面的api-platform-interface提供的一些接口进行简单测试,先不做复杂校验,后续流程调通再根据实际业务需求做复杂逻辑校验)
后端设计
controller:新增一个接口调用接口实现,并定义InterfaceInfoInvokeRequest作为接口调用请求参数
// 1.接口调用请求参数定义
@Data
public class InterfaceInfoInvokeRequest {
/**
* 主键
*/
private Long id;
/**
* 用户请求参数
*/
private String userRequestParams;
private static final long serialVersionUID = 1L;
}
// 2.接口信息新增接口调用调试入口
public class InterfaceInfoController {
@PostMapping("/invoke")
public BaseResponse<Object> invokeInterfaceInfo(@RequestBody InterfaceInfoInvokeRequest interfaceInfoInvokeRequest,
HttpServletRequest request) {
// 检查请求对象是否为空或者接口id是否小于等于0
if (interfaceInfoInvokeRequest == null || interfaceInfoInvokeRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
// 获取接口id
long id = interfaceInfoInvokeRequest.getId();
// 获取用户请求参数
String userRequestParams = interfaceInfoInvokeRequest.getUserRequestParams();
// 判断是否存在
InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
if (oldInterfaceInfo == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
}
// 检查接口状态是否为下线状态
if (oldInterfaceInfo.getStatus() == InterfaceInfoEnum.OFFLINE.getValue()) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "接口已关闭");
}
// 获取当前登录用户的ak和sk,相当于用户自己的这个身份去调用,因为知道是谁刷了这个接口,不会担心它刷接口,会比较安全
User loginUser = userService.getLoginUser(request);
String accessKey = loginUser.getAccessKey();
String secretKey = loginUser.getSecretKey();
// 只需要进行测试调用,所以我们需要解析传递过来的参数。
Gson gson = new Gson();
// 参考接口上线的实现,此处使用api-platform-client-sdk实现接口调用
com.noob.apiclientsdk.model.User user = gson.fromJson(userRequestParams, com.noob.apiclientsdk.model.User.class);
ApiClient invokeApiClient = new ApiClient(accessKey,secretKey);
// 通过invokeApiClient调用getUserNameByPostBySign方法获取响应数据
String res = invokeApiClient.getUserNameByPostBySign(user);
// 返回成功响应,并包含调用结果
return ResultUtils.success(res);
}
}
前端设计
# 借助yarn run openapi生成接口调用交互请求代码,随后在InterfaceInfo/index.tsx中引入
import { invokeInterfaceInfoUsingPost } from '@/services/api-platform-backend/interfaceInfoController';
// 1.引入在线调用响应相关参数配置(用于响应状态处理和相应结果展示参数封装)
const [invokeRes, setInvokeRes] = useState<any>();
const [invokeLoading, setInvokeLoading] = useState(false);
// 2.优化调用测试响应结果处理方法onFinish,实现调用后台接口返回响应数据
// 在线调试表单测试
const onFinish = async (values: any) => {
// alert('请求调用测试');
// console.log('Success:', values);
if (!params.id) {
message.error('接口不存在');
return;
}
setInvokeLoading(true);
try {
// 发起接口调用请求,传入一个对象作为参数,这个对象包含了id和values的属性(id 是从 params 中获取的,而 values 是函数的参数)
const res = await invokeInterfaceInfoUsingPost({
id: params.id,
...values,
});
setInvokeRes(res.data);
message.success('请求成功');
} catch (error: any) {
message.error('操作失败,' + error.message);
}
setInvokeLoading(false);
};
// 3.新增Card组件用于展示相应结果
<Card title="返回结果" loading={invokeLoading}>
{invokeRes}
</Card>
接口调用测试
测试:上线接口、模拟请求进行在线调用测试。此处需注意原api-platform-interface的实现只是初步构建模拟测试的接口,实际还没有对数据操作做交互(例如一些accessKey、secretKey的交互),因此测试的时候如果出现无权限提示(相应匹配对应数据库的ak、sk配置),注意打断点跟踪相关的接口调用信息,此外还需注意请求参数和响应参数配置的设定
如果传入中文会出现乱码问题,导致通过body生成sign不同无法通过验证,通过参数编解码的方式解决中文参数传递乱码问题
解决中文乱码问题:
api-platform-client-sdk:
api-platform-interface:
待优化点
- 判断该接口是否可以调用时由固定方法改为根据测试地址来调用
- 用户测试接口固定方法名改为根据测试地址来调用
- 模拟接口改为从数据库校验 ak、sk
扩展点
用户可以申请更换签名(如果用户的签名泄露,用户有权申请更换签名)。
先跑通整个接口流程,后续可以针对不同的请求头或者接口类型来设计界面和表单,给用户更好的体验(可以参考 swagger、postman、knife4j)。