- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
最近新接手了一批项目,还没来得及接新需求,一大堆bug就接踵而至,仔细一看,应该返回数组的字段返回了 null ,或者没有返回,甚至返回了字符串 "null" ???
这我能忍?我立刻截图发到群里,用红框加大加粗重点标出。后端同学也积极响应,答应改正.
第二天,同样的事情又在其他的项目上演,我只是一个小前端,为什么什么错都找我啊!! 。
日子不能再这样下去,于是我决定写一个工具来解决遇到 bug 永远在找前端的困境.
如何对接口数据进行校验呢,因为我们的项目是 React+TypeScript 写的,所以第一时间就想到了使用 TypeScript 进行数据校验。但是众所周知,TypeScript 用于编译时校验,有没有办法作用到运行时呢?
我还真找到了一些运行时类型校验的库: typescript-needs-types ,大部分需要使用指定格式编写代码,相当于对项目进行重构,拿其中 star 最多的 zod 举例,代码如下.
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 。
export interface IUserInfo {
staffId: number
name: string
email: string
}
然后创建 src/types/index.ts 文件并引入刚才的类型.
import { IUserInfo } from './user';
interface ILabel {
id: number;
name: string;
color: string;
remark?: string;
}
type ILabelArray = ILabel[];
type IUserInfoAlias = IUserInfo;
接下来在 package.json 添加脚本 。
"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 格式.
{
"$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 校验数据,我找到了现成的库 ajv ,至于为什么选择 ajv,主要是因为它说它很快,详见: https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance 。
接下来尝试一下。我找到了中文版文档,有兴趣的可以去看下 http://www.febeacon.com/ajv-docs-zh-cn/.
先安装依赖 npm install ajv ,然后创建文件 src/validate.ts 。
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 添加下面代码来测试一下.
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 :
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 发送的请求.
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 :
{
"user": { "staffId": 1, "name": "cookie1", "email": "cookie@cookie.com" },
"labels": [
{
"id": 1,
"name": "ck",
"color": "red",
"remark": "blabla"
},
{
"id": 2,
"color": "green"
}
]
}
再在 package.json 添加脚本 。
"scripts": {
"serve": "json-server --watch db.json -p 8000"
},
现在执行 npm run serve 就可以启动服务器了。在 src/index.tsx 增加调用接口的代码,并引入 src/interceptTool.ts .
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 然后添加内容 。
export const urlMapType = {
'http://localhost:8000/user': 'IUserInfoAlias',
'http://localhost:8000/labels': 'ILabelArray',
}
我们在 src/validate.ts 新增函数 validateDataByUrl 。
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 文件中引用 。
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 的情况,如果能自动赋值 [] ,就可以防止前端页面崩溃的情况了.
最后此篇关于如何优雅地校验后端接口数据,不做前端背锅侠的文章就讲到这里了,如果你想了解更多关于如何优雅地校验后端接口数据,不做前端背锅侠的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
1. HTML 结构 1.1 HTML 文件基本结构 第一个html程序 hello world! html 标签是整个 h
文件上传三种方案:1. form表单上传,2. iframe,3. FormData,base64上传文件,二进制流上传文件,二进制流下载文件。异步上传,大文件上传--切片:拆分上传请求断点续传显示上
1. HTML 结构 1.1 HTML 文件基本结构 第一个html程序 hello world! html 标签是整个 h
uniapp作为开发移动端的前端框架,目前国内是非常流行的,使用HbuilderX开发工具基于uniapp框架开发的系统可以方便的转换为小程序、APP等移动端程序,大大降低了移动开发的成本。网络
今天我们来复盘一下前端中css伪元素的知识以及如何用css伪元素来减轻javascript的压力,做出一些脑洞大开的图形。 预备知识 伪元素 伪元素是一个附加至选择器末的
今天给大家分享一些实用的JS代码片段,有需要的朋友欢迎收藏! 1、获取浏览器的版 functiongetBrowser(){ varUserAgent=navigator.us
1 . Wappalyzer 全球用户数:1,000,000+ Wappalyzer可以帮助我们了解目标网站的构建方式。工作当中存在大量此类情况,客户需要我们参照某些网站
在管理后台中我们会使用大量的表格表单组件, 导入导出各种报表, 有些场景还需要对报表数据进行可视化分析, 动态生成可视化图表, 笔者将基于以上场景, 总结一些实用的 Table 组件开发技巧,
3D动画效果现在越来越普及,已经被广泛的应用到了各个平台,比如阿里云,华为云,webpack官网等。它可以更接近于真实的展示我们的产品和介绍,带来极强的视觉冲击感。所以说,为了让自己更加优秀,c
QShop商城-快速开始-前端 工具准备 NodeJs 前端环境为NodeJs,下载地址:http://nodejs.cn/download/current/ 。 默认会用版
1. 初始JavaScript 1.1 什么是 JavaScript JavaScript (简称 JS) 是世界上最流行的编程语言之一 是一个脚本语言, 通过解释器运行 主要在客户端(浏览器)上运行
1. WebAPI 背景知识 1.1 什么是 WebAPI JS 分成三个大的部分: ECMAScript: 基础语法部分 DOM API: 操作页面结构 BOM API: 操作浏览器 WebAPI
1. WebAPI 背景知识 1.1 什么是 WebAPI JS 分成三个大的部分: ECMAScript: 基础语法部分 DOM API: 操作页面结构 BOM API: 操作浏览器 WebAPI
1. 初始JavaScript 1.1 什么是 JavaScript JavaScript (简称 JS) 是世界上最流行的编程语言之一 是一个脚本语言, 通过解释器运行 主要在客户端(浏览器)上运行
有没有办法从页面访问 tomcat 服务器日志?如果有一些方法或实现可以做到这一点...... 最佳答案 PSI Probe可以列出您的 Tomcat 日志文件并显示它们的内容。您可以采用相同的方法,
我想知道是否有一些很好的免费网站性能分析工具,特别是前端。这主要是关于Javascript的。 现有工具(例如 Google Pagespeed)的问题在于它不适用于我的应用程序。在进入我的应用程序之
我曾经遇到一个 MySQL 前端应用程序,它在父行中显示外部链接行,例如,如果 Client 表有一个指向 Suburb 表的外键: (来源:vb123.com) 您知道可以执行此操作的任何前端吗?
我正在建立一个带有管理区域的网上商店来管理产品。在管理区域中,所有产品都是可见的,但在网上商店中,只有数据库表中标记为 active = 1 的产品是可见的。 我正在使用 Silex 并将存储库注册为
有可能在 C# 中制作 GUI,但在 C 或 C++ 中制作实际程序。 比如说我想制作一个聊天应用程序。我希望界面在 C# 中。但我想用 C 编写所有实际代码。这可能吗? 我找到了 http://ww
对于我自己的教育,我很好奇编译器使用哪个 C++ 前端和后端。您能告诉我以下技术在哪里使用以及它们有哪些标志/优势(如果有的话)? Open64 - 它是后端、前端还是两者兼而有之?哪些编译器使用它?
我是一名优秀的程序员,十分优秀!