前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何优雅地校验后端接口数据,不做前端背锅侠

如何优雅地校验后端接口数据,不做前端背锅侠

作者头像
科技新语
发布于 2023-02-07 10:00:00
发布于 2023-02-07 10:00:00
1.4K00
代码可运行
举报
运行总次数:0
代码可运行

背景

最近新接手了一批项目,还没来得及接新需求,一大堆bug就接踵而至,仔细一看,应该返回数组的字段返回了 null,或者没有返回,甚至返回了字符串 "null"???

这我能忍?我立刻截图发到群里,用红框加大加粗重点标出。后端同学也积极响应,答应改正。

第二天,同样的事情又在其他的项目上演,我只是一个小前端,为什么什么错都找我啊!!

日子不能再这样下去,于是我决定写一个工具来解决遇到 bug 永远在找前端的困境。

TypeScript 运行时校验

如何对接口数据进行校验呢,因为我们的项目是 React+TypeScript 写的,所以第一时间就想到了使用 TypeScript 进行数据校验。但是众所周知,TypeScript 用于编译时校验,有没有办法作用到运行时呢?

我还真找到了一些运行时类型校验的库:typescript-needs-types,大部分需要使用指定格式编写代码,相当于对项目进行重构,拿其中 star 最多的 zod 举例,代码如下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { z } from "zod";

const User = z.object({
  username: z.string(),
});

User.parse({ username: "Ludwig" });

// extract the inferred type
type User = z.infer<typeof User>;
// { username: string }

我宁可查 bug 也不可能重构手里一大堆项目啊。此种方案 ❎。

此时看到了 typescript-json-schema 可以把 TypeScript 定义转为 JSON Schema ,然后再使用 JSON Schema 对数据进行校验就可以啦。这种方案比较灵活,且对代码入侵性较小。

搭建一个项目测试一下!

使用 npx create-react-app my-app --template typescript 快速创建一个 React+TS 项目。

首先安装依赖 npm install typescript-json-schema

创建类型文件 src/types/user.ts

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export interface IUserInfo {
  staffId: number
  name: string
  email: string
}

然后创建 src/types/index.ts 文件并引入刚才的类型。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { IUserInfo } from './user';

interface ILabel {
  id: number;
  name: string;
  color: string;
  remark?: string;
}

type ILabelArray = ILabel[];

type IUserInfoAlias = IUserInfo;

接下来在 package.json 添加脚本

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"scripts": {
    // ...
    "json": "typescript-json-schema src/types/index.ts '*' -o src/types/index.json --id=api --required --strictNullChecks"
}

然后运行 npm run json 可以看到新建了一个 src/types/index.json 文件(此步在已有项目中可能会报错报错,可以尝试在 json 命令中添加 --ignoreErrors 参数),打开文件可以看到已经成功转成了 JSON Schema 格式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "$id": "api",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "ILabel": {
            "properties": {
                "color": {
                    "type": "string"
                },
                "id": {
                    "type": "number"
                },
                "name": {
                    "type": "string"
                },
                "remark": {
                    "type": "string"
                }
            },
            "required": [
                "color",
                "id",
                "name"
            ],
            "type": "object"
        },
        "ILabelArray": {
            "items": {
                "$ref": "api#/definitions/ILabel"
            },
            "type": "array"
        },
        "IUserInfoAlias": {
            "properties": {
                "email": {
                    "type": "string"
                },
                "name": {
                    "type": "string"
                },
                "staffId": {
                    "type": "number"
                }
            },
            "required": [
                "email",
                "name",
                "staffId"
            ],
            "type": "object"
        }
    }
}

使用 JSON Schema 校验数据

至于如何使用JSON Schema 校验数据,我找到了现成的库 ajv,至于为什么选择 ajv,主要是因为它说它很快,详见:github.com/ebdrup/json…

接下来尝试一下。我找到了中文版文档,有兴趣的可以去看下 www.febeacon.com/ajv-docs-zh…

先安装依赖 npm install ajv,然后创建文件 src/validate.ts

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import Ajv from 'ajv';
import schema from './types/index.json';

const ajv = new Ajv({ schemas: [schema] });

export function validateDataByType(type: string, data: unknown) {
  console.log(`开始校验,类型:${type}, 数据:`, data);

  var validate = ajv.getSchema(`api#/definitions/${type}`);
  if (validate) {
    const valid = validate(data);
    if (!valid) {
      console.log('校验失败', validate.errors);
    }
    else {
      console.log('校验成功');
    }
  }
}

接下来在 src/index.tsx 添加下面代码来测试一下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
validateDataByType('IUserInfoAlias', {
  email: 'idonteatcookie@gmail.com',
  name: 'idonteatcookie',
  staffId: 12306
})

validateDataByType('IUserInfoAlias', {
  email: 'idonteatcookie@gmail.com',
  staffId: 12306
})

validateDataByType('IUserInfoAlias', {
  email: 'idonteatcookie@gmail.com',
  name: 'idonteatcookie',
  staffId: '12306'
})

可以在控制台看到成功打印如下信息:

拦截请求

因为项目中发送请求都是调用统一封装的函数,所以我首先想到的是在函数中增加一层校验逻辑。但是这样的话就与项目代码耦合严重,换一个项目又要再写一份。我真的有好多项目QAQ。

那干脆拦截所有请求统一处理好了。

很容易的找到了拦截所有 XMLHttpRequest 请求的库 ajax-hook,可以非常简单地对请求做处理。

首先安装依赖 npm install ajax-hook,然后创建 src/interceptTool.ts

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { proxy } from 'ajax-hook';
export function intercept() {
  // 获取 XMLHttpRequest 发送的请求
  proxy({
    onResponse: (response: any, handler: any) => {
      console.log('xhr', response.response)
      handler.next(response);
    },
  });
}

这样就拦截了所有的 XMLHttpRequest 发送的请求,但是我突然想到我们的项目,好像使用 fetch 发送的请求来着???

好叭,那就再拦截一遍 fetch 发送的请求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export function intercept() {
  // ...
  const { fetch: originalFetch } = window;
  // 获取 fetch 发送的请求
  window.fetch = async (...args) => {
    const response = await originalFetch(...args);
    response.clone().json().then((data: { result: any }) => {
      console.log('window.fetch', args, data);
      return data;
    });
    return response;
  };
}

为了证明拦截成功,使用 json-server 搭建一个本地 mock 服务器。首先安装 npm install json-server,然后在根目录创建文件 db.json

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "user": { "staffId": 1, "name": "cookie1", "email": "cookie@cookie.com" },
  "labels": [
    {
      "id": 1,
      "name": "ck",
      "color": "red",
      "remark": "blabla"
    },
    {
      "id": 2,
      "color": "green"
    }
  ]
}

再在 package.json 添加脚本

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"scripts": {
  "serve": "json-server --watch db.json -p 8000"
},

现在执行 npm run serve 就可以启动服务器了。在 src/index.tsx 增加调用接口的代码,并引入 src/interceptTool.ts

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { intercept } from './interceptTool';
// ... other code
intercept();

fetch('http://localhost:8000/user');

const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8000/labels');
xhr.send();

可以看到两种请求都拦截成功了。

校验接口返回数据

胜利在望,只差最后一步,校验返回数据。我们校验数据需要提供两个关键信息,数据本身和对应的类型名,为了将两者对应起来,需要再创建一个映射文件,把 url 和类型名对应起来。

创建文件 src/urlMapType.ts 然后添加内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export const urlMapType = {
  'http://localhost:8000/user': 'IUserInfoAlias',
  'http://localhost:8000/labels': 'ILabelArray',
}

我们在 src/validate.ts 新增函数 validateDataByUrl

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { urlMapType } from './urlMapType';
// ...
export function validateDataByUrl(url: string, data: unknown) {
  const type = urlMapType[url as keyof typeof urlMapType];
  if (!type) {
    // 没有定义对应格式不进行校验
    return;
  }
  console.log(`==== 开始校验 === url ${url}`);
  validateDataByType(type, data);
}

然后在 src/interceptTool.ts 文件中引用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { proxy } from 'ajax-hook';
import { validateDataByUrl } from './validate';

export function intercept() {
  // 获取 XMLHttpRequest 发送的请求
  proxy({
    onResponse: (response, handler: any) => {
      validateDataByUrl(response.config.url, JSON.parse(response.response));
      handler.next(response);
    },
  });

  const { fetch: originalFetch } = window;
  // 获取 fetch 发送的请求
  window.fetch = async (...args) => {
    const response = await originalFetch(...args);
    response.json().then((data: any) => {
      validateDataByUrl(args[0] as string, data);
      return data;
    });
    return response;
  };
}

现在可以在控制台看到接口数据校验的接口辣~ ✿✿ヽ(°▽°)ノ✿

总结下流程图

后续规划

目前所做的事情,准确的说不是拦截,只是获取返回数据,然后对比打印校验结果,因为初步目标不涉及数据的处理。

后续会考虑对不合法的数据进行处理,比如应该返回数组但是返回了 null 的情况,如果能自动赋值 [],就可以防止前端页面崩溃的情况了。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
零售店海量固定资产管理方案
零售店本来相关业务比较多,随着业务量的增长,对于仓库信息化管理要求比较高,仓库的枢纽作用日益显现,不断出库、入库的实物资产给员工带来压力。而且随着固定资产数量的日益增多、员工的流转都给管理带来了压力。稍有不慎,就会出现出入库效率低,实物与账务不符,库存闲置率高,重复采购,盘点效率低,盘点准确率差,还出现了商品丢失的现象。
易点易动固定资产管理系统
2023/02/21
2410
零售店海量固定资产管理方案
固定资产管理流程和技巧
企业固定资产是保证企业正常运行的重要基础物质条件,其管理及核算状况影响对企业业务活动的开展,经济效益的提高。从目前实际情况看,企业在固定资产管理,核算等方面存在诸多问题,因此,加强企业固定资产管理成为不容忽视的问题。
易点易动固定资产管理系统
2021/08/16
7090
易点易动打通企业固定资产采购,为企业降本增效
在当今经济形势下,企业面临着日益激烈的竞争压力。为了在市场中脱颖而出,降低成本、提高效率成为了企业发展的重要课题。
易点易动固定资产管理系统
2023/03/21
3800
易点易动打通企业固定资产采购,为企业降本增效
易点易动——打通财务和采购,实现一站式管理固定资产
固定资产对于企业的重要性不言而喻,它是企业的重要生产要素。对固定资产的有效管理,不仅关系到企业的经营效益,还关系到企业的合规性和风险控制。然而,在实际固定资产管理工作中,很多企业面临着以下固定资产管理的难题:
易点易动固定资产管理系统
2023/03/16
3390
易点易动——打通财务和采购,实现一站式管理固定资产
固定资产管理系统--企业降本增效的必备工具
随着公司业务和规模的日益扩大,公司的固定资产数量和种类也随之扩大和增长。这就给固定资产管理和盘点工作带来了一定的挑战。对于大型的企业而言,由于实物资产数量的庞大,传统的手工盘点和表格管理固定资产的方式已不能满足固定资产管理的需求,管理出错的风险也不断提高。而且由于无法实现信息化管理,固定资产的重复采购率和闲置率也居高不下,这无疑增加了企业的运营成本。
易点易动固定资产管理系统
2021/11/05
4610
固定资产管理系统--企业降本增效的必备工具
盘点五大好用的固定资产管理系统
随着各行各业对固定资产管理的重视,越来越多的企业和事业单位开始使用固定资产管理系统来高效化管理固定资产,以提高实物资产的利用率,降低固定资产的流失率。但对于初次使用固定资产管理系统的企业而言,可能不太清楚哪种固定资产管理系统更加适合自己。小编今天为大家复盘一下市场上的固定资产管理系统,希望对大家的固定资产管理系统选型有所帮助~
易点易动固定资产管理系统
2021/08/19
3K0
为什么说手工表格管理固定资产已经OUT了?
以电子表格、纸质数据为主的传统固定资产管理和盘点的方式已被各种各样的固定资产管理系统所取代。人工管理的弊端和缺陷如下:
易点易动固定资产管理系统
2021/09/18
5810
为什么说手工表格管理固定资产已经OUT了?
固定资产管理系统的优势
如果行政人员、IT人员、财务人员想把固定资产管理这个工作做好,离不开一个有利的固定资产管理工具。固定资产管理系统为企事业单位提供全方位、可靠、高效的动态管理方式,助力企业实现固定资产的信息化、规范化和标准化管理。它能助力企业提升固定资产管理和盘点的效率,使固定资产管理和盘点变得轻松和准确。
易点易动固定资产管理系统
2021/09/09
6650
固定资产管理系统让企业动态掌握资产情况
很多企业经常会因为固定资产信息分散、查询不便、信息反映实效性差、纸质文档不易保存等问题导致资产流失、重复购买严重等问题,从而导致企业成本大幅度提升。越来越多的企业开始使用专业的固定资产管理系统,它可以将企业的固定资产信息、人员信息、部门信息等进行整合,还可以实现多层级和多组织架构的管理,实现固定资产的统筹管理,从而整合企业资产信息,提升固定资产利用率,减少重复采购并避免资产流失。
易点易动固定资产管理系统
2022/06/29
3810
固定资产管理系统让企业动态掌握资产情况
企业为什么要使用固定资产管理系统?
小编在对国内200家公司进行固定资产管理的调研的过程中发现,虽然85%的企业已经很重视固定资产的管理和盘点,但是其中超过50%的企业在管理的过程中存在流程和方法的问题。企业普遍存在的问题有:固定资产重复采购严重、闲置率高、丢失率高、盘点效率低、盘点成本高等。另外,因为固定资产信息不能实时更新,有些集团公司中也存在一些问题。比如:有的分公司有闲置的固定资产,但是分公司却一直采购,资源无法共享。
易点易动固定资产管理系统
2021/08/11
5580
说说IT企业固定资产管理系统的问题和解决方法
IT企业随着业务的扩大、人员的增多,企业的固定资产数量和种类都会随之越来越多。当IT企业发展到一定规模后,内部管理通常会遇到一些问题:
易点易动固定资产管理系统
2021/12/13
6990
说说IT企业固定资产管理系统的问题和解决方法
如何在固定资产管理的路上乘风破浪?
目前,随着企业发展内部的需求推动,加上外界环境的多变,更多企业越来越重视,不但要降本增效为企业发展助力,而且要加速智能化发展的步伐。然而,要加强企业不同细分领域的智能化发展需要循序渐进,非一朝一夕之功。
易点易动固定资产管理系统
2021/08/13
3170
易点易动固资管理软件解决固定资产管理员的难题
固定资产管理一直是企业管理中的比较棘手的问题。随着企业规模的扩大,员工人数和固定资产的数量也不断增多,传统的固定资产管理方式的弊端日益突显。久而久之,会造成企业固定资产管理的混乱:资产台账与事实不符造成审计困难和资产的浪费、资产履历无法追溯造成资产丢失、纸质审核和纸质表格盘点效率低下、资产信息更新不及时、资产无法共享导致重复采购率高等问题。
易点易动固定资产管理系统
2022/07/19
4220
易点易动固资管理软件解决固定资产管理员的难题
企业数字化转型, RFID固定资产管理系统不可或缺
在企业普遍加快信息化进程的当下,越来越多的企业开始注重企业内部的管理。比如客户管理、合同管理、固定资产管理等。越来越多的企业摆脱了手工管理模式,开始引入各种系统给企业信息化助力。固定资产管理系统也被引入到企业的管理中。采用现代的云计算技术、条码、二维码技术、RFID等技术与相应的硬件扫描技术相结合,优化了固定资产的全生命周期管理流程,极大地提高了企业实物资产的管理和盘点效率,降低固定资产重复采购和丢失率,提升固定资产的利用率,为企业实现降本增效。
易点易动固定资产管理系统
2021/10/15
4850
企业数字化转型, RFID固定资产管理系统不可或缺
上线固定资产管理系统,节约固定资产采购成本
南京某互联网公司是一家高科技公司,随着公司业务的不断扩大,公司在不同的城市都有了分支机构,公司员工数量也在增加。固定资产的数量和种类都在增加,而且不同分支机构的调动也比较频繁,给固定资产管理带来了一定的难度。公司决定上线一套固定资产管理系统解决方案。在经过多方市场调研之后,公司选择了易点易动固定资产管理系统。
易点易动固定资产管理系统
2022/03/18
6330
上线固定资产管理系统,节约固定资产采购成本
如何直击固定资产管理的难题?
根据调查显示,200人以上的企业因缺乏完善的智能管理系统,每年会导致10-15%的固定资产流失率,20%左右的资产闲置率以及10%的固定资产重复采购率。这些都会给企业的运营带来不好的影响,直接增加了企业的运营成本,造成了资源的浪费。易点易动不仅可以将企业资产管理得井井有条,还能做到100%解决资产流失、闲置、重复采购等资源浪费的问题。
易点易动固定资产管理系统
2022/08/03
2480
如何直击固定资产管理的难题?
集团公司固定资产管理的痛点和解决方案
集团公司的固定资产往往因为分支机构多,无法统筹管理,而且资产数量较多、种类较为复杂、人员总数较大且流动频繁而较难管理和盘点。在小编走访的若干集团公司中,固定资产管理往往存在以下的几个痛点:
易点易动固定资产管理系统
2022/05/24
6530
集团公司固定资产管理的痛点和解决方案
2022年最好用的5款固定资产系统
2022年的第一个季度转瞬即逝。各企业在疫情反复中迎来了第二个季度。在经济大形势不稳定以及疫情反复的局势之下,各企业主今年的主要任务依然是“开源”和“节流”。作为企业开支的重要组成部分,固定资产的管理尤为重要。如何进行固定资产管理和盘点,各企业也是八仙过海各显神通:有EXCEL大神依旧使用EXCEL管理的,也有在OA或者财务系统中使用固定资产管理菜单进行管理的,还有一大部分企业已经引入了各种固定资产管理系统进行固定资产管理和盘点的。目前市面上有各种固定资产管理系统:有单机版、网络版、SaaS版、本地部署版等。根据条码的不同还可以分为:条形码、二维码、RFID码。
享搭低代码平台
2022/03/28
1.7K0
2022年最好用的5款固定资产系统
固定资产管理系统对企业的意义?
越来越多的企业开始放弃使用EXCEL表格,而使用固定资产管理系统来管理企业的固定资产了。因为随着企业规模扩大、人员增多,固定资产数量和种类以及存放地点都在直线增加,如果还在使用表格管理固定资产,效率明显跟不上公司发展的节奏。为了提升工作效率,让企业的固定资产日常管理更加流畅,企业管理者纷纷采用适合自己业务需求的固定资产管理软件进行实物资产的全生命周期管理和定期盘点。
易点易动固定资产管理系统
2022/08/11
2930
固定资产管理系统对企业的意义?
上线固定资产管理系统会给企业带来哪些好处?
随着企业的固定资产也变得越来越多,固定资产的管理者会发现使用传统模式进行管理不能满足现在的需求,为了完善企业固定资产管理体系,确保企业从员工到管理层都重视固定资产管理,确保企业的实物资产运转正常,实现固定资产的完整、保值、高利用率,越来越多的企业开始部署固定资产管理系统,来智能化管理和盘点固定资产,为企业降本增效,增强企业在市场的竞争力。
易点易动固定资产管理系统
2021/11/12
4090
上线固定资产管理系统会给企业带来哪些好处?
推荐阅读
相关推荐
零售店海量固定资产管理方案
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验