在Node.js和前端项目中,Ajv是最常用的JSON Schema校验库之一。当我们需要验证某个字段是不是合法的URI时,通常会使用format关键字并指定为uri。但不少人在实际使用中发现,一些自认为没问题的字符串却被Ajv判定为非法。这背后涉及Ajv所依据的RFC3986规范以及人们对URI格式的直觉偏差。

一、Ajv中的URI格式类型
Ajv通过ajv-formats插件提供支持多种URI相关格式,常见包括:
- uri:绝对URI,必须符合RFC3986定义的absolute-URI或URI规则,包含scheme。
- uri-reference:允许相对引用,可以是相对路径。
- uri-template:URI模板格式。
其中uri是最严格的,很多误区也来自这里。
二、RFC3986规范要点
RFC3986规定一个典型的URI结构为:
scheme://authority/path?query#fragment
几个容易忽略的点:
1. 主机名不能包含下划线
很多人写http://my_host.com以为合法,但RFC3986的host规则不允许下划线,Ajv会报错。
2. 相对路径不是uri
字符串/api/v1/users对uri格式非法,但可以通过uri-reference校验。
3. 空格必须编码
未编码空格在URI中不被允许,应写成%20。
三、Ajv校验示例
下面代码展示在Node环境中使用Ajv校验URI:
const Ajv = require('ajv');
const addFormats = require('ajv-formats');
const ajv = new Ajv();
addFormats(ajv);
const schema = {
type: 'object',
properties: {
link: { type: 'string', format: 'uri' }
}
};
const validate = ajv.compile(schema);
// 合法示例
console.log(validate({ link: 'https://ipipp.com/docs?ref=1' })); // true
// 非法示例:含空格
console.log(validate({ link: 'https://ipipp.com/hello world' })); // false
// 非法示例:相对路径
console.log(validate({ link: '/relative/path' })); // false
四、常见误区与处理
误区一:localhost不带点号
http://localhost:3000在浏览器中可用,但严格按RFC3986,authority中的host若用名称则应含点号或属于IP。Ajv默认可能通过,因为reg-name规则较宽松,但若使用较严实现会失败。建议测试环境使用http://127.0.0.1:3000。
误区二:误用uri-reference
如果业务允许填相对地址,应使用uri-reference而非uri,否则用户填./config.json会被拒。
误区三:忘记引入ajv-formats
Ajv 8之后format不再内置,必须显式调用addFormats(ajv),否则format: 'uri'不会生效,导致任何字符串都通过。
五、自定义格式补充
若你的系统允许下划线主机,可自定义format:
const ajv = new Ajv();
ajv.addFormat('loose-uri', {
type: 'string',
validate: (s) => /^https?://[w.-]+(:d+)?(/.*)?$/.test(s)
});
const schema = { type: 'string', format: 'loose-uri' };
const validate = ajv.compile(schema);
console.log(validate('http://my_host.com/path')); // true
理解Ajv与RFC3986的关系,能帮你少踩很多参数校验的坑。根据业务需要选择uri或uri-reference,并确认formats插件已加载,就可以稳健地完成URI合法性检查。
AjvURI_validationRFC3986修改时间:2026-07-27 04:57:21