在上一篇《JSON文件的应用》中我说过,从客户端上传到服务器上的JSON字符串是需要校验的。这篇博文的主要内容包含JSON字符串为什么需要校验,以及如何校验等。
大家都知道,服务器是非常宝贵的公共资源。因此,对于服务器上的文件应该具有更加严格的要求。针对JSON文件,主要有以下两个方面:
主要举两个例子:
①如果因为客户端程序的问题,向服务器传回了一份有缺陷的JSON字符串(比如括号不匹配,丢失逗号分隔符等)。
②如果同样是因为客户端程序的问题,向服务器传回的JSON字符串中,用户联系人里面有一个人居然没有ID和姓名。
总之,客户端是不可信的,如果服务器程序直接将上述JSON字符串覆盖回用户对应的JSON文件里,那么这个用户可能每次打开以这个账户登录APP都会闪退,甚至只能重新申请一个新的账号。
试想,如果一个恶意攻击者将一段包含Shell命令的字符串——而不是正确的JSON字符串——传到了服务器。那么可能他只需用这个账户登录APP就可以获得服务器的控制权,这简直是灾难!
因此,无论出于哪方面考虑,我们都必须对从客户端传到服务器的JSON字符串进行校验。
JSON Schema用来描述JSON数据格式。它有多种用途,其中之一就是实例验证。验证过程可以是交互式或非交互式的。例如,应用程序可以使用JSON模式来构建用户界面使互动的内容生成除了用户输入检查或验证各种来源获取的数据。[1]
网上的概念比较晦涩难懂。按照我的理解,JSON Schema类似于抽象语法树。至于它长什么样,后面我会给出一个具体的例子。
下面这段JSON字符串在《JSON文件的应用》中贴过,为了便于说明,再贴一次。
{
"contacters": [
{
"id": "10101",
"name": "张三",
"age": 22,
"singleOrNot": true
},
{
"id": "10102",
"name": "李四",
"age": 24
}
]
}
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"required": [
"contacters"
],
"properties": {
"contacters": {
"$id": "#/properties/contacters",
"type": "array",
"title": "The Contacters Schema",
"items": {
"$id": "#/properties/contacters/items",
"type": "object",
"title": "The Items Schema",
"required": [
"id",
"name",
"age", //注①
"singleOrNot"
],
"properties": {
"id": {
"$id": "#/properties/contacters/items/properties/id",
"type": "string",
"title": "The Id Schema",
"default": "",
"examples": [
"10101"
],
"pattern": "^(.*)$"
},
"name": {
"$id": "#/properties/contacters/items/properties/name",
"type": "string",
"title": "The Name Schema",
"default": "",
"examples": [
"张三"
],
"pattern": "^(.*)$"
},
"age": {
"$id": "#/properties/contacters/items/properties/age",
"type": "integer",
"title": "The Age Schema",
"default": 0,
"examples": [
22
]
},
"singleOrNot": {
"$id": "#/properties/contacters/items/properties/singleOrNot",
"type": "boolean",
"title": "The Singleornot Schema",
"default": false,
"examples": [
true
]
}
}
}
}
}
}
注释:
①age和singleOrNot应该删掉,因为它们和id、name不同,不是必须的。被"required"
约束的属性,每个成员必须具有。但是在我们的例子中,有些联系人我们是不需要记录他的年龄和是否单身的,因此这两个属性不是必须的。否则会因此发生校验失败。
这里给大家介绍一个网站——JSON Schema Tool,我们可以用它来生成自己的JSON Schema。
我们只需要在左边的Your JSON*
输入框输入自己的JSON字符串(需要语法正确),然后点击INFER SCHEMA
按钮,即可看到右边生成的JSON Schema。
需要注意的是,右边一共三个选项卡,我们复制中间的那个里面的Schema字符串就可以了,第一个是一种树形结构,第三个复制出来会带有行号。
在服务端校验JSON文件需要执行以下的步骤:
保存刚刚生成的Schema字符串到一个文件(如UserSchema.json
),所有用户记录的校验都依赖于该文件。
要校验JSON需要先引入json-schema-validator
的依赖。在pom.xml
文件的
标签中添加以下代码:
<dependency>
<groupId>com.github.fgegroupId>
<artifactId>json-schema-validatorartifactId>
<version>2.2.6version>
dependency>
public ProcessingReport validate(String dataString, String schemaString) {
ProcessingReport processingReport = null;
try {
JsonNode dataNode = JsonLoader.fromString(dataString);
JsonNode schemaNode = JsonLoader.fromString(schemaString);
JsonSchema schema = JsonSchemaFactory.byDefault().getJsonSchema(schemaNode);
processingReport = schema.validate(dataNode);
return processingReport;
} catch (IOException | ProcessingException ex) {
Logger.getLogger(JsonService.class.getName()).log(Level.SEVERE, null, ex);
}
return processingReport;
}
函数会返回一个ProcessingReport
类型的对象,调用该对象的isSuccess
函数返回的boolean
值即表示校验成功或失败。然后就可以根据这个结果来决定要不要用这份客户端上传的新用户记录来覆盖老的用户记录了。
JSON的校验其实可以相当复杂,可以看到JSON Schema Tool
为我们生成的JSON Schema框架里面有一个属性叫"pattern"
:
"pattern": "^(.*)$"
很明显它是一个无意义的正则表达式,如果我们需要更加严格的校验规则(比如年龄限定在0-120
以内),就需要修改这个正则表达式或者其他的属性。而这部分的知识,应该又是一本小册子的事情了,学到了再更新。
摘自百度百科——jsonschema ↩︎