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 中的各个部分,以及如何进行防御式编程来避免恶意攻击。正则表达式是前端开发的基础技能之一,能够帮助我们快速解决很多问题,但也需要注意正则表达式的使用风险,并进行进一步的防御。
 极客笔记
极客笔记