别人写的平台再垃圾,也是用来淘汰你的。
Python环境没有的,请自行安装,本教程采用的是python 3.9。
Django官网 https://www.djangoproject.com/
Node环境没有的,请自行安装,本教程采用的是node v17.6.0。
Vue.js官网 https://cn.vuejs.org/
接着上章,本章将完成接口的调试功能。
接口管理模块开发(七)
环境管理主要逻辑
上章完成的新增功能中可以看到接口只保存了路径,没有域名端口等信息,大概的设想是将其保存在环境信息中,选择不同的环境请求不同的IP/域名、端口。
因此在完成接口调试功能前先完成「环境管理」的增删改查功能,因为没有复杂的业务处理,可以查看前面的「项目管理模块开发」系列,这里不再进行详细介绍,主要步骤如下:
- 在后端项目中定义Model类,然后使用DRF的
ModelViewSet
快速定义接口,最后设置路由
- 在前端项目中新增页面,并且新增路由指向新页面,然后在新页面上使用Table组件进行数据展示;定义增删改查接口,并在相应的按钮事件中进行调用。
接口调试功能
环境管理功能开发完成后,就可以开始进行接口调试功能开发了。主要交互如下:
- 新增下拉框用于选择环境
- 选择环境后,点击接口信息右侧的【Send】按钮,将环境信息和当前页面的接口信息通过接口传给后端接口
- 后端接口中根据环境信息和接口信息进行处理后,使用
requests
模块访问接口 - 将接口返回的信息进行封装,按照「完整请求」、「响应内容」、「响应头」三部分进行返回
后端接口定义
- 首先后端自定义一个
ApiSendView
继承APIView
,然后定义一个post方法用来提供一个post类型的接口。 - 因为接口信息跟接口保存的参数一致,可以使用ApiSerializer进行解析。而环境信息需要单独从请求体中获取。
class ApiSendView(APIView):
def post(self, request):
api = ApiSerializer(request.data).instance
env = ''
if 'env' in request.data:
env = request.data['env']
- 因为要使用
requests
模块来发送请求,因此需要先安装requests
(参考前面章节,不再赘述),安装完成后,在项目目录下新增一个utils
目录存放项目用到的工具,然后在utils
下新增一个request_util.py
文件,专门用来处理请求,新增方法用来拼接请求参数和处理响应数据,具体代码如下。
def request_by_api(env: Env, api: Dict) -> Response:
return request_by_domain(domain=env.domain,
protocol=env.protocol,
port=env.port,
path=api["path"],
params=api["params"],
body=api["body"],
body_type=api["body_type"],
headers=api["headers"],
method=api["method"]
)
def request_by_domain(
domain: str,
port: str,
path: str,
params: str,
body: str,
headers: str,
protocol: str = "HTTP",
body_type: str = "NONE",
method: str = "GET") -> Response:
url = f"{
protocol.lower()}://{
domain}"
if port:
url += f":{
port}"
url += path
req_params = {
}
if len(params) > 0:
for param in params:
req_params[param['param_key']] = param['value']
req_headers = {
}
if len(headers) > 0:
for header in headers:
req_headers[header['param_key']] = header['value']
if method == "GET":
return request(method, url, headers=req_headers, params=req_params)
else:
if body_type == "JSON":
return request(method=method, url=url, params=params, headers=headers, json=body)
else:
return request(method=method, url=url, params=params, headers=headers, data=body)
def response_handler(resp:Response):
# 进行请求封装
result = {
"body": resp.content,
"headers": resp.headers,
"content":
f"""{
resp.request.method} {
resp.request.url} {
resp.status_code}
请求头:{
resp.request.headers}
请求体:{
resp.request.body}"""
}
return result
- 接着在新接口中使用工具类进行请求和响应的处理,如下:
class ApiSendView(APIView):
def post(self, request):
api = ApiSerializer(request.data).instance
env = ''
if 'env' in request.data:
env = request.data['env']
env = Env.objects.get(id=env)
resp = request_util.request_by_api(env, api)
return Response(request_util.response_handler(resp))
到这里接口就处理完毕了,接下来完成前端的交互。
前端页面交互
首先新增下拉框展示所有的环境信息,效果如下图:
- 新增变量保存环境列表数据,在
onMounted
方法中调用接口查询环境列表。
const envs = ref([]);
onMounted(() => {
listApi().then((res) => {
envs.value = res;
});
});
- 然后在
select
组件中展示所有的环境信息。
<a-select placeholder="请选择环境">
<a-select-option v-for="env in envs" :key="env.id" :value="env.id">{
{
env.name
}}</a-select-option>
</a-select>
- 最终效果如下:
然后给【Send】按钮添加点击事件,将环境信息和当前填写的接口信息作为接口参数。
import {
addApiApi, apiSendApi} from "../../apis/api";
const sendApi = () => {
// 获取请求体
if (apiBodyRef.value) {
formState.value.body_type = apiBodyRef.value.body_type;
formState.value.body = apiBodyRef.value.getData();
if (formState.value.body === "") {
formState.value.body_type = "NONE";
}
}
// 测试环境
if (enviroment.value) {
formState.value.env = enviroment.value;
}
apiSendApi(formState.value).then((res) => {
console.log(res);
});
};
重启项目,刷新页面,选择环境后进行接口调试,可以看到控制台成功输出响应信息。接下来就是将响应信息中的响应体、响应头、请求内容展示在对应的tab中。
前端结构优化(状态管理)
在获取响应数据之前,先来对前端结构进行优化,避免组件之前传值过程过于复杂。
首先来看下当前ApiListView页面存在问题,为了防止ApiListView页面功能过多导致文件过大,因此对不同的部分进行了组件拆分,随之而来的是组件之前传值的问题。
- 例如接口详情,首先在
ApiListSider
组件中获取到接口ID,然后传递到父组件ApiListView
,再由父组件ApiListView
传递给子组件ApiContent
,接着再将请求参数传递给子组件ApiParams
,最后传递给TableForm
用于展示。其他字段,比如请求头、请求体也是如此,操作链路非常长。 - 例如接口调试获得了响应信息,首先在
ApiListSider
组件中获取到响应信息,将响应头给子组件resBody
,然后传递给Coder
,其他字段,比如响应头,请求内容也是如此。
上诉问题有两个解决方案:
1、将子组件引用链缩短,例如ApiListContent直接使用TableForm展示请求头信息,去掉ApiParams组件。其他字段也是如此。
2、使用pinia
进行状态管理,这样状态信息就不再需要在组件链上传递,只需要在要使用时访问状态即可。
因为使用脚手架搭建项目框架已经选择安装了pinia
依赖,所以无需安装(没有的,请自行进行安装)。
按接口调试的响应信息举例:
- 首先在前端项目
src/stores
下新增api.js
文件用来存放接口管理相关的状态。
import {
ref } from "vue";
import {
defineStore } from "pinia";
export const useApiResponseStore = defineStore("apiResponse", () => {
const resBody = ref("");
const resHeaders = ref([]);
const reqContent = ref("");
const updateResponse = (data) => {
resBody.value = data["body"];
resHeaders.value = data["headers"];
reqContent.value = data["content"];
};
return {
resBody, resHeaders, reqContent, updateResponse };
});
- 在组件
ApiListView
中直接调用updateReponse
方法更新响应信息。
const apiResponse = useApiResponseStore();
const sendApi = () => {
...
apiSendApi(formState.value).then((res) => {
apiResponse.updateResponse(res);
});
};
- 在组件
ResBody
中直接使用apiResponse.resBody
获取保存的状态信息
<template>
<div class="res-body">
<api-coder
:lang="'json'"
:initHeight="'250px'"
:content="apiResponse.resBody"
@updateScript="updateContent"
></api-coder>
</div>
</template>
<script setup>
import ApiCoder from "@/components/ApiCoder.vue";
import {
useApiResponseStore } from "../../stores/api";
const apiResponse = useApiResponseStore();
const updateContent = (content) => {
apiResponse.resBody = content;
};
</script>
重启项目,刷新页面,再次选择环境后,进行接口调试功能,可以看到resBody可以正常展示响应数据了,如下图:
响应头和请求内容也是按照上面的步骤进行处理,从状态中直接获取信息,不再进行组件之间数据的传递,实现后效果如下。
篇幅有限,接口调试功能就结束啦,前面使用通过组件间传递的信息都可以使用状态管理进行改造,大家可自行进行修改。下节将继续接口的增删改查功能,敬请期待~