input[type="url"]校验不可靠,仅作基础whatwg解析,不拦相对路径或非法协议;必须前端trim()后用url.canparse()预检,后端用原生url解析器严格校验并白名单控制。

别信 input[type="url"] 能替你把关——它只做最基础的 WHATWG 解析,连空格都处理不好,更不拦相对路径或非法协议。
为什么 input[type="url"] 校验不可靠
浏览器对它的处理,本质就是悄悄调用一次 new URL(value) 并忽略异常。这意味着:
-
example.com(缺协议)直接失败,但//cdn.example.com(协议相对 URL)却算“合法” -
http:/example.com(少一个/)报错,https://(无主机)也报错,但ftp://files可能过 - 用户从微信粘贴的
" https://a.com "带首尾空格,它会静默截断,既不触发:invalid伪类,也不抛错 - iOS Safari 和旧版 Android WebView 中,
type="url"可能被完全忽略,键盘照常弹文本框
用 URL.canParse() 做轻量级预检
比 new URL() 更安全、不抛异常,适合快速判断是否“看起来像绝对 URL”:
- 它只校验字符串能否被解析为绝对 URL,不支持相对路径(如
/api、./page) - 调用方式简单:
URL.canParse(s.trim()),必须先trim(),否则含空格直接返回false - 兼容性注意:Chrome 94+、Firefox 91+、Safari 16.4+ 支持;旧环境需降级到
try { new URL(...) } catch - 它不检查协议是否真实(
foo://也能过),也不管域名能不能解析,仅作格式守门员
手动 new URL() + 属性校验才是业务刚需
真正要 enforce HTTPS、限定域名后缀、排除 localhost,必须主动构造并读取属性:
- 先
trim(),再new URL(s),捕获TypeError判定基础格式 - 成功后立刻检查:
url.protocol === 'https:'、url.hostname.endsWith('.mycompany.com')、!url.href.includes(' ') - 中文域名(如
https://例.com)会被自动转 Punycode,但输入未编码的 Unicode 在 Safari 16.4 之前可能失败 - 不要用正则替代它——
localhost:3000、https://[::1]、带 query 的路径,正则极易漏判或回溯爆炸
后端校验不是可选项,是必须项
前端任何逻辑都可被绕过:禁 JS、改 DOM、curl 直发请求。后端必须独立执行:
- 同样先
trim(),再用语言原生 URL 解析器:filter_var($url, FILTER_VALIDATE_URL)(PHP)、urllib.parse.urlparse()(Python)、new URL()(Node.js) -
FILTER_VALIDATE_URL遵循 RFC 3986,比前端更严格,支持 IPv6 和 IDN 域名 - 输出时若用于重定向,必须走白名单机制,不能拼接用户输入的原始
url.hostname或url.pathname - 别信“已前端校验了”,没后端兜底的 URL 输入,等于裸奔
最易被忽略的点:空格和不可见字符(比如 U+200B)在粘贴场景高频出现,trim() 必须出现在前端校验、后端解析、甚至数据库存储前——少一次,就可能让 new URL() 突然崩溃或绕过业务规则。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











