前端输入转义那些坑 一次实战经验分享

Prog.逸龙 安全 阅读 746
赞 52 收藏
二维码
手机扫码查看
反馈

优化前:卡得不行

大家好,今天想和大家分享一下我在项目中遇到的一个性能问题,以及我是如何一步步优化的。这个项目是一个内部管理系统,用户在输入框里输入数据时,需要进行一些安全转义处理,防止XSS攻击。一开始没太注意,结果页面加载时间居然飙到了5秒多,用户体验简直不能更差了。

前端输入转义那些坑 一次实战经验分享

找到瘼颈了!

首先我用Chrome DevTools的Performance面板测了一下,发现主要的瓶颈在于输入框的数据转义处理。每次用户输入数据,系统都会调用一个转义函数来处理,这导致CPU占用率非常高,而且页面响应速度非常慢。

具体来说,我在输入框的oninput事件里绑定了一个处理函数,每输入一个字符就触发一次转义操作。这样的设计虽然逻辑简单,但性能确实拉胯。

优化方法一:批量转义

试了几种方案,第一个想到的是批量转义。也就是说,不每次输入都转义,而是等用户输入完毕后再一次性转义。这样可以减少转义次数,降低CPU占用。

代码改动如下:

// 优化前
const input = document.querySelector('input');
input.addEventListener('input', (e) => {
  const value = e.target.value;
  const escapedValue = escapeHtml(value);
  // 处理其他逻辑
});

// 优化后
const input = document.querySelector('input');
let timeoutId;

input.addEventListener('input', (e) => {
  clearTimeout(timeoutId);
  timeoutId = setTimeout(() => {
    const value = e.target.value;
    const escapedValue = escapeHtml(value);
    // 处理其他逻辑
  }, 300); // 300ms后批量转义
});

function escapeHtml(unsafe) {
  return unsafe
    .replace(/&/g, "&")
    .replace(//g, ">")
    .replace(/"/g, """)
    .replace(/'/g, "'");
}

这样改完之后,页面响应速度确实快了不少,加载时间从5秒降到了大概2秒左右。不过还是不够理想,用户还是能感觉到明显的延迟。

优化方法二:使用模板引擎内置的转义功能

后来又尝试了另一种方案,就是利用模板引擎内置的转义功能。我们项目用的是Vue.js,Vue本身就有内置的转义机制,可以直接在模板中使用v-html指令来渲染转义后的HTML内容。

代码改动如下:


<div id="app">
  <input v-model="userInput" @input="handleInput">
  <div>{{ escapedValue }}</div>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    userInput: '',
    escapedValue: ''
  },
  methods: {
    handleInput() {
      this.escapedValue = escapeHtml(this.userInput);
    }
  }
});
</script>

// 优化后
<div id="app">
  <input v-model="userInput">
  <div v-html="escapedUserInput"></div>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    userInput: ''
  },
  computed: {
    escapedUserInput() {
      return this.escapeHtml(this.userInput);
    }
  },
  methods: {
    escapeHtml(unsafe) {
      return unsafe
        .replace(/&/g, "&")
        .replace(//g, ">")
        .replace(/"/g, """)
        .replace(/'/g, "'");
    }
  }
});
</script>

这样一来,Vue会在渲染时自动处理转义,不需要我们在事件处理器里手动转义。页面加载时间进一步降到1秒左右,感觉流畅多了。

优化方法三:Web Worker

最后还尝试了一个方案,就是把转义操作放到Web Worker里去执行。这样可以避免阻塞主线程,进一步提升性能。

代码改动如下:

// main.js
const input = document.querySelector('input');
const worker = new Worker('worker.js');

input.addEventListener('input', (e) => {
  worker.postMessage(e.target.value);
});

worker.onmessage = function(e) {
  const escapedValue = e.data;
  // 处理其他逻辑
};

// worker.js
self.onmessage = function(e) {
  const value = e.data;
  const escapedValue = escapeHtml(value);
  self.postMessage(escapedValue);
};

function escapeHtml(unsafe) {
  return unsafe
    .replace(/&/g, "&")
    .replace(//g, ">")
    .replace(/"/g, """)
    .replace(/'/g, "'");
}

用了Web Worker之后,页面加载时间进一步降到800毫秒左右,效果非常好。不过这里有个小坑要注意,就是在传递大量数据时,可能会有性能损失,所以要根据实际情况来选择是否使用。

性能数据对比

经过几次优化,最终的效果如下:

  • 优化前:页面加载时间5秒左右
  • 优化方法一:页面加载时间2秒左右
  • 优化方法二:页面加载时间1秒左右
  • 优化方法三:页面加载时间800毫秒左右

从数据上看,优化效果非常明显,用户体验也得到了极大的提升。

结尾

以上就是我在实际项目中对输入转义性能优化的一些经验分享。希望对大家有所帮助,如果你们有更好的方案或者遇到过类似的问题,欢迎在评论区交流。后续还会继续分享更多实战经验,敬请期待。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论