在《如何使用 JavaScript 解析 URL?》一文中介绍过 URL 地址的解析方法。而我们的日常开发中,另一个会时常遇到的应用场景应该是如何使用 JavaScript 校验字符串是否为合法的 URL 地址?今天这篇文章应该算是《如何使用 JavaScript 解析 URL?》一文的姊妹篇了,我们来看看 URL 地址合法性的判断思路又是怎么样的。
URL 格式
要校验 URL 地址的合法性,当然我们还是需要(再次)回顾以下一个合法的 URL 地址格式是怎么样的?
完整的 URL 信息包括以下几点:
- 协议(protocol):采用的协议方案;
- 登录信息(username & password):(可选项)指定用户名和密码,用来从服务器获取资源时的认证信息;
- 服务器地址(hostname):待访问的服务器地址。可以是域名形式也可以是 IP 地址;
- 服务器端口号(port):;指定服务器连接网路的端口号;
- 带层次的文件路径(pathname):指定服务器上的文件路径来定位特指的资源;
- 查询字符串(search):(可选项)查询字符串参数;
- 片段标识符(hash):(可选项)用来标记已获取资源中的子资源;
正则表达式
不像解析 URL 地址,JavaScript 中并没有提供校验 URL 合法性的内置方法。《如何使用 JavaScript 解析 URL?》中介绍的 URL 构造函数,虽然提供了一个静态方法:URL.canParse(),但无奈的是目前这个方法的浏览器支持情况实在太差。
所以目前还只能使用正则表达式的方式来判断字符串是否为合法的 URL 格式。根据前文介绍的 URL 格式的内容,使用 JavaScript 的正则表达式表示大致如下:
/^((protocol):)?\/\/((username):(password)@)?(hostname)(:(port))?(pathname)(\\?(search))?(#(hash))?/
实际的 JavaScript 正则表达式代码实现则是这样的:
const pattern = /^(([^:/?#]+):)?\/\/(([^/?#]+):(.+)@)?([^/?#:]*)(:(\d+))?([^?#]*)(\\?([^#]*))?(#(.*))?/
isURL() 方法实现
虽然前文已经给出了一个完整的 JavaScript 正则表达式,但在实际实现 isURL() 方法的时候,我们并不会直接这么处理。因为上面的正则表达式比较复杂,如果你使用 Sonarlint 之类的工具对前文的正则表达式进行代码扫描,会提示该正则表达式的复杂度超标了,过于复杂。建议将表达式拆分为职责更简单的子表达式。
所以,在 types.js 项目中,将大而全的正则表达式拆分为以下实现:
const _getURLPattern = () => {
const protocol = '(\\w+:)?'
const user = '([^\\/\\?\\#\\:]+)'
const password = '(.+)'
const auth = '(' + user + ':' + password + '@)?'
const address = '(([a-z\\d]([a-z\\d-]*[a-z\\d])*(\\.)?)+[a-z]{2,})'
const ip = '((\\d{1,3}\\.){3}\\d{1,3})'
const hostname = '(' + address + '|' + ip + ')'
const port = '(\\:\\d+)?'
const host = '(' + hostname + port + ')'
const pathname = '((\\/[-a-z\\d%_.~+]*)*)'
const search = '(\\?[;&a-z\\d%_.~+=-]*)?'
const path = '(' + pathname + search + ')*'
const hash = '(\\#[-a-z\\d_]*)?'
const url = '^' + protocol + '\\/\\/' + auth + host + path + hash + '$'
return new RegExp(url, 'i')
}
export default _getURLPattern
这么一调整,每个子表达式的职责就很单一,复杂度就大大降低了。而代码的可读性和可维护性也是明显的有了提升。
Ok,一切准备就绪,完整的 isURL() 方法实现如下:
import isString from './isString'
import _getURLPattern from './_getURLPattern'
/**
* 判断字符串是否为有效的 URL 地址
* ========================================================================
* @method isURL
* @category Lang
* @param {String} str - 要检测的字符串
* @returns {Boolean} 'val' 是有效的 URL 字符串格式,返回 true,否则返回 false
*/
const isURL = (str) => {
const pattern = _getURLPattern()
return isString(str) && !!pattern.test(str)
}
export default isURL
结束语
希望通过此文,对于初学 JavaScript 的同学了解如何使用 JavaScript 校验字符串是否为合法的 URL 地址有所帮助。同时也期待 JavaScript 内置的方法能得到所有主流浏览器的支持。当然,如果你有什么更好的解决思路,也欢迎留言评论。
0 条评论