input[type="url"]不可靠,仅粗略检查结构;应配合required、trim()及new URL()或PHP filter_var()做后端校验,并按业务白名单限制域名与协议。

input[type="url"] 不能当作可靠校验手段,它只拦得住明显乱输(比如 abc 或空值),但放得过大量“结构上勉强像 URL”的输入——比如 foo://bar、https:///example.com、www.example,甚至带中文路径的原始字符串。
为什么 input[type="url"] 总是“看起来能用,实际拦不住”
浏览器内部只检查是否含冒号+双斜杠+点号这类粗粒度结构,不验证协议是否存在、域名能否解析、路径是否符合 RFC 3986。它本质是个轻量提示控件,不是校验器。
- 必须搭配
required才能管“有没有”,否则空值也能提交 - 移动端粘贴时若带首尾空格或换行符,原生校验直接失效
- Safari 和旧版 Android WebView 对它的行为不一致,错误提示时机和文案都可能不同
- 它对相对路径(如
/api/data)或file:///、git://这类协议完全不设防
用 pattern 能补多少?怎么写才不翻车
可以有限增强,但正则要避开几个经典坑:浏览器会自动给 pattern 加上 ^ 和 $,你不能再自己写;它也不校验空格,所以仍需 JS 配合 trim()。
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 强制 http/https 开头:
pattern="https?://[^\s/$.?#].[^\s]*"(末尾必须有[^\s]*,否则http://a b也能过) - 别抄网上“匹配所有 URL”的超长正则——容易回溯爆炸,或拒绝
localhost:3000、https://例.com这类合法地址 -
pattern只对type="url"生效,但它和原生校验逻辑并存,冲突时表现难预测
JS 里用 new URL() 比正则更靠谱
现代浏览器中,new URL(string) 会真正尝试解析,遇到格式非法就抛 TypeError,比手写正则稳定得多,代码也更短。
- 必须先
string.trim(),否则" https://a "直接报错 - 只用于绝对 URL 校验;如果业务允许相对路径(如
/login),就别用它 - 示例函数:
function isValidUrl(s) { try { new URL(s.trim()); return true; } catch (_) { return false; } } - 注意:它仍不查 DNS、不验证书、不判断是否可访问,只是格式守门员
后端 PHP 必须独立做 filter_var($url, FILTER_VALIDATE_URL)
前端任何验证都可被绕过——禁用 JS、改 DOM、curl 直发请求,都能跳过所有前端逻辑。PHP 端不能信任 $_POST['url'] 已“被过滤过”。
- 必须先
trim(),否则带空格的字符串直接失败 -
FILTER_VALIDATE_URL遵循 RFC 3986,支持 IPv6、中文域名等合法格式,比手写正则可靠 - 若只要 HTTP/HTTPS,再用
parse_url()提取scheme并限定为in_array($parsed['scheme'], ['http', 'https']) - 空字符串、仅空白字符、协议后无内容(如
https://)都会返回false,需单独处理
最容易被忽略的一点:URL 格式合法 ≠ 安全可用。哪怕 filter_var() 和 new URL() 都通过了,仍要按业务场景做白名单限制(比如只允许 GitHub 域名)、DNS 可解析性检查、甚至 HTTPS 证书验证——这些都得在后端做,且不能省。

















