JS也有地域你知道吗?

97 阅读2分钟

正则导致浏览器回溯地狱

const isURL = str => {

  const reg = /^((https?|ftp|file)://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-]*)*/?$/;
  return reg.test(str);

};

// 使用这个方法判断这个string会导致页面崩溃
isURL('https://xx.cn/bizmember/enterprise/license_index?fr=maiin_index'))

这个正则表达式看起来有些问题,可能导致浏览器陷入回溯地狱(Catastrophic Backtracking),这会消耗大量计算资源,使浏览器变慢,甚至导致页面崩溃。为了避免这个问题,您可以使用一个更简单且有效的正则表达式来验证URL。这里有一个示例:

javascriptCopy code
const isURL = (str) => {
  const reg = /^(?:(?:https?|ftp)://)?(?:\S+(?::\S*)?@)?(?:(?!10(?:.\d{1,3}){3})(?!127(?:.\d{1,3}){3})(?!169.254(?:.\d{1,3}){2})(?!192.168(?:.\d{1,3}){2})(?!172.(?:1[6-9]|2\d|3[0-1])(?:.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i;
  return reg.test(str);
};

console.log(isURL('https://xx.cn/bizmember/enterprise/license_index?fr=maiin_index'));

这个正则表达式应该可以正确地验证URL,并且不会导致浏览器出现性能问题。请注意,正则表达式可能不是绝对完美的,可能会有一些边缘情况未被涵盖。然而,对于大多数用途,它应该已经足够好了。

浏览器陷入回溯地狱是什么bug,是什么原因导致的呢?什么情况下会有这个问题

回溯地狱(Catastrophic Backtracking)是一种正则表达式处理过程中可能遇到的问题。它发生在正则表达式引擎试图匹配一个复杂的模式时,而这个模式具有大量可选的组合。这种情况下,正则表达式引擎可能会消耗大量的时间和计算资源尝试所有可能的匹配方式。如果存在太多的组合,这可能导致浏览器变慢、冻结甚至崩溃。

回溯地狱通常发生在以下几种情况:

  1. 存在多个重复操作符(如 *, +{n,})在同一正则表达式中。
  2. 存在嵌套的分组和量词,这会增加匹配的可能性。
  3. 存在大量的分支或可选项,这会导致正则表达式引擎尝试许多不同的匹配路径。

避免回溯地狱的一些建议:

  1. 尽量避免在正则表达式中使用嵌套的分组和重复操作符。
  2. 使用非贪婪量词(如 *?+?{n,}?)来减少匹配的可能性。
  3. 使用原子分组或预测否定来确保某些子表达式匹配之后不会再发生回溯。
  4. 优化正则表达式,减少不必要的组合和分支。

在编写正则表达式时,务必关注性能,确保不会出现回溯地狱。测试正则表达式的性能,尤其是在处理大量或复杂的数据时,可以帮助预防这种问题的发生。