URL 正则表达式
在前端开发中,我们经常需要提取 URL 中的一些信息,例如域名、参数等等。这时候,我们就可以使用正则表达式来快速匹配 URL 中的各个部分。
URL 结构
一个标准的 URL 包含以下几个部分:
<scheme>://<user>:<password>@<host>:<port>/<path>?<query>#<fragment>
scheme表示 URL 的协议,例如http、https、ftp等等。user和password分别表示访问 URL 所需的账号和密码。host表示主机名,可以是域名或者 IP 地址。port表示端口号,默认为80。path表示 URL 请求的路径,可以包含多个层级的目录和文件名。query表示 URL 的查询参数,可以传递多个键值对,使用&分隔。fragment表示 URL 的锚点,用于页面定位跳转。
提取 URL 中的信息
提取域名
使用正则表达式提取 URL 中的域名,例如把 https://www.baidu.com/index.html 地址中的 www.baidu.com 提取出来。正则表达式如下:
const url = 'https://www.baidu.com/index.html';
const pattern = /^[^/]+\/\/[^/]+/;
const domain = url.match(pattern)[0];
console.log(domain); // https://www.baidu.com
我们使用正则表达式 ^[^/]+\/\/[^/]+,其中:
^表示匹配行首。[^/]表示匹配除了/以外的任意字符。+表示匹配前面的字符 1 次或多次。\/\/表示匹配//。[^/]+同上。
注意,在提取出的域名后面应该加上 //,否则后面的请求会出错。
提取 URL 参数
我们经常需要在 URL 中传递参数,这时候可以使用正则表达式来获取这些参数。例如,把 https://www.baidu.com/search?q=javascript&sort=vote&page=2 地址中的参数提取出来。正则表达式如下:
const url = 'https://www.baidu.com/search?q=javascript&sort=vote&page=2';
const pattern = /\?(\S*)/;
const paramsStr = url.match(pattern)[1];
console.log(paramsStr); // q=javascript&sort=vote&page=2
我们使用正则表达式 \?(\S*),其中:
\?表示匹配?。(\S*)表示匹配非空白字符 0 次或多次,并用圆括号将结果捕获到分组中。
注意,取出分组中的参数字符串后,还需要进行进一步的处理,以便提取出每个键值对的具体信息。
提取 URL 中特定的参数值
在获取 URL 参数之后,有时候需要提取参数中特定键的值。例如,把 https://www.baidu.com/search?q=javascript&sort=vote&page=2 地址中的 q 参数提取出来。正则表达式如下:
const url = 'https://www.baidu.com/search?q=javascript&sort=vote&page=2';
const pattern = /q=([^&]*)/;
const value = url.match(pattern)[1];
console.log(value); // javascript
我们使用正则表达式 q=([^&]*),其中:
q=表示匹配q=。[^&]*表示匹配非&字符 0 次或多次,并用圆括号将结果捕获到分组中。
注意,在进行正则匹配时,应该首先判断 URL 是否包含该参数,如果存在则再截取参数的值。
const url = 'https://www.baidu.com/search?q=javascript&sort=vote&page=2';
const paramName = 'q';
const pattern = new RegExp(`${paramName}=([^&]*)`);
const match = url.match(pattern);
if (match) {
const value = match[1];
console.log(value); // javascript
}
我们使用 RegExp 构造函数动态生成正则表达式,其中:
${paramName}表示插入变量paramName的值。=表示匹配=。([^&]*)同上。
注意,在使用动态正则表达式时,要谨慎处理转义字符,确保最终生成的正则表达式是正确的。
URL 防御式编程
由于 URL 是由用户输入的,存在恶意用户输入攻击 URL 的风险,因此我们还应该进行防御式编程,避免代码被注入攻击。
URL 校验
首先,我们需要对用户输入的 URL 进行校验,确保 URL 的合法性。可以使用正则表达式来验证 URL。
const url = 'https://www.baidu.com/index.html';
const pattern = /^(http|https|ftp):\/\/[\w\-]+(\.[\w\-]+)*([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?$/;
if (pattern.test(url)) {
console.log('URL is valid.');
} else {
console.log('URL is invalid.');
}
我们使用正则表达式 ^(http|https|ftp):\/\/[\w\-]+(\.[\w\-]+)*([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?$,其中:
^表示匹配行首。(http|https|ftp)表示匹配http、https或ftp。:\/\/表示匹配://。[\w\-]+表示匹配字母、数字、下划线、连字符,至少匹配 1 次。(\.[\w\-]+)*表示匹配.后面跟字母、数字、下划线、连字符,至少匹配 0 次(即可以没有)。加上圆括号表示可以匹配多个这样的字符串。([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?表示匹配 URL 路径和查询参数部分。$表示匹配行尾。
注意,该正则表达式可以过滤掉一些字符,但并不能完全消除恶意攻击,因此需要进行进一步的防御。
URL 编码和解码
由于 URL 中可以包含一些特殊字符,而浏览器对这些字符的解释不一定相同,因此我们需要对 URL 进行编码和解码,以保证浏览器的解释结果一致。
// 编码
const url = 'https://www.baidu.com/search?q=javascript&sort=vote&page=2';
const encodedUrl = encodeURI(url);
console.log(encodedUrl); // https://www.baidu.com/search?q=javascript&sort=vote&page=2
// 解码
const decodedUrl = decodeURI(encodedUrl);
console.log(decodedUrl); // https://www.baidu.com/search?q=javascript&sort=vote&page=2
我们使用 encodeURI 和 decodeURI 方法对 URL 进行编码和解码,其中:
encodeURI方法可编码 URL 中除字符A~Z a~z 0~9 - _ . ! ~ * ' ( ) ; : @ & = + $ , / ? # [ ]以外的所有字符,编码后的字符使用%加 ASCII 码的 16 进制表示,例如空格编码后为%20。decodeURI方法可解码encodeURI编码的字符。
注意,在进行 URL 编码和解码时,应该谨慎处理字符串中包含的特殊字符,确保最终的编码和解码结果是正确的。
总结
本文介绍了如何使用正则表达式来提取和处理 URL 中的各个部分,以及如何进行防御式编程来避免恶意攻击。正则表达式是前端开发的基础技能之一,能够帮助我们快速解决很多问题,但也需要注意正则表达式的使用风险,并进行进一步的防御。
极客笔记