求一个验证url合法性的正则,网上找了很多都有漏洞

点点乐淘淘
  • 332

求一个验证url合法性的正则,网上找了很多都有漏洞,如下面这个:

function IsURL(str_url){
    var strRegex = '^((https|http|ftp|rtsp|mms)?://)'
            +'?(([0-9a-z_!~*().&=+$%-]+: )?[0-9a-z_!~*().&=+$%-][email protected])?' //ftp的[email protected]
            + '(([0-9]{1,3}.){3}[0-9]{1,3}' // IP形式的URL- 199.194.52.184
            + '|' // 允许IP和DOMAIN(域名)
            + '([0-9a-z_!~*()-]+.)*' // 域名- www.
            + '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].' // 二级域名
            + '[a-z]{2,6})' // first level domain- .com or .museum
            + '(:[0-9]{1,4})?' // 端口- :80
            + '((/?)|' // a slash isn't required if there is no file name
            + '(/[0-9a-z_!~*().;?:@&=+$,%#-]+)+/?)$';
    var re=new RegExp(strRegex);
    if (re.test(str_url)){
        return (true);
    }else{
        return (false);
    }
}
IsURL("sfas") //居然返回true
IsURL("http://www.baidu.com") //这个也是true

再看这个:

var regex =/^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?$/i;
regex.test('http://www.sina/') //true

上面的都有问题,求高手给一个能用的?

回复
阅读 14.7k
5 个回答
litchilab
  • 206
✓ 已被采纳

很遗憾的告诉你,正则表达式检测url合法性正则检测远比你想象中的要复杂的多。我的建议是:把url限制在一个范围里面,之后再用get请求根据返回的http状态码来检测这个url是否存在来检测是否能达到你的要求。
我给你解释一下为什么给你这样的建议:
url组成部分什么的我就不说了。想要检测url你要检测:

1.协议(协议不能决定url是否合法,除非强制url带有协议)、但是协议的数量很少,10个手指数的过来,很好使用正则做判断。
2.域名:想要检测域名是否合法,检测的部分分为域名前缀、域名名称和后缀(扩展名)。因为现在的域名名称中可以包含中文、日文、阿拉伯文(可能还有我不知道的),后缀也是一样。
例如【にっぽんこく.com】这样一个域名虽然目前不能访问,但是是合法的。例如【xxxx.中国】也是合法的。就目前所知道的域名后缀数量有882个之多。里面包含了我说的域名所包含的语言。
3.端口、用户名、密码。事实上一个带有用户名、密码和端口号的url也可能是合法的。例如www.baidu.com:80,或者http://username:[email protected]/path/index.html
这种形式的url也是合法的。你现在看到的网站网址没有用户名和密码是因为浏览器以匿名用户向服务器发送请求,并且服务器没有任何限制。但是带有用户名和密码的url就是合法的。
3.path部分。url的资源路径,以及可能携带查询参数,或者带有#标记的fragment。例如:www.baidu.com:80/path/233.html?query=xxxx&query2=xxxx#some
这种url也是合法的。
4.参数查询中的标点。www.example.com?qyuer=lily's blog 这个是合法的,不过会对url进行编码,空格会被转义成带有%的十六进制数字表示。http://www.example.com/?qyuer...
这两个url是一样的。

所以,你想在网上找一个url合法性检测的正则表达式是不可能做到十分全面的。
如果你有兴趣可以按照上面的思路自己实现一个。

判断域名的长度,一个域名最长的长度为:255个字节(包括标点符号)。域名名称最长63字节,比如example.com example部分最长63字节。域名后缀最长13个字节(目前)。如果你还想判断语言的话可以对不通语言的域名后缀长度做判断,例如域名后缀的判断:([a-z]{2,13}|[x{4e00}-x{9fa5}]{2,3})。
url中的用户名和密码可以限定在一定长度内。然后协议判断:有协议的是否在限定的范围内,如果没有可以默认为http协议。
一般判断url合法只是为了防止恶意输入,如果你想知道该url是否可以正常访问最好的方式还是发送get请求根据http状态码做判断。爬虫就是这么干的。不过可能会遇到国内服务器因为防火墙的缘故国外的url访问不了的情况,所以建议使用美国服务器或者香港的对url进行检测。

关于域名扩展数量你可以这里:https://www.key-systems.net/e...

不过你要是伸手党,就当我没说。

reg = /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-][email protected])?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-z_!~*'()-]+.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].[a-z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+\/?)$/;

把上面函数里的正则这样改一下是可以的,url中必须带有协议才能通过

agui1989
  • 4.6k

看了一下正则,有个明显的错误:

+ '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].' // 二级域名
//应该是:
+ '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\.' // 二级域名

这里应该是要有个点的,但正则中的点是.,而不是. 。

注意:. 匹配除换行符 n 之外的任何单字符。要匹配 . ,请使用 . 。

其它的就不多说了,合法的url基本上没有什么限制,除了知道至少是这样:
基本上是任意字符+点+基本上是任意字符+随便你怎么写,可能都是参数

比如楼主写的就没有考虑中文域名的情况。

另外,楼上 kumfo 结的 npm包用了 nodejs的url包,在浏览器中就不能使用了。

ezmo
  • 7k

可以负责任的告诉你,找不到符合你条件的正则。
就比如 www.sina你说它是合法还是不合法呢?你想说它不合法,因为域名后缀不对。 域名后缀数量奇多,如果想把所有合法域名后缀都加上,这个正则会超级长! cn,com, io, org,us,ca,me,ink, xyz,in,pro,studio,news, app...各种后缀层出不穷,全部穷举一遍,做不到,每天都在更新。 除非你只关心指定的几种后缀,才能判断www.sina是不是合法。 到底后缀有多少,看看这个网站就知道了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏