跳至主要內容

Da-API平台-接口发布、在线调用

holic-x...大约 22 分钟项目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组件库open in new window查阅组件用法,随后直接基于基础组件构建自己想要的页面即可

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 添加路由,动态路由可以查看官网 —— UmiJSopen in new window,给这个路由新增两个参数:

  • 让这个路由可以接收动态参数,在点击查看之后可以跳到对应的接口页面,通过 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组件,选择合适的组件完善页面信息,类似描述列表组件open in new window等,参考官网实现,复制代码即可

​ 完成上述操作,查看接口信息,后续可提供一个在线调用的接口供用户测试

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)。

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3