共计 2213 个字符,预计需要花费 6 分钟才能阅读完成。
一个奇怪的 Bug
非常感谢小赵同学给我反馈的这个 Bug 🙌🙌
在开始解说前先考考你们 Javascript 根底,单看代码你感觉它会输入什么内容?答案前面揭晓。
'Hello'.replace('ello', '#$&%')
话说某一天我忽然收到一封邮件,一位同学跟我说我的站点炸代码了,吓得我忽然就从床上翻了个身——感觉充电线有点勒脖子我又翻了回去……
一波详询过后我理解到是我的自建博客站点,也就是当初在写文章的这个,它在某个页面上会显示一部分代码在页面的下方。像这样:
情绪忽然就不好了——死去的 Bug 忽然又回来攻打我了。。
这个问题其实之前呈现过,但我起初给修好了,明天又呈现了我第一工夫就放松复现,但发现我本人拜访如同没啥问题,定位到最初发现是我的服务端的渲染脚本的问题。所以如果你是间接进入站点再浏览文章是不会遇到的,多半我之前就是这样才认为它修复了吧。复现的形式也很简略:你得间接由某个链接进入到某一篇博文才会触发,这就很有意思啦!根本能够阐明它是因为数据的起因才会触发的。
因为我这个服务端渲染是本人用 Express 写的,不是用的现成的框架,所以有的中央可能是会有问题的也失常。在一波摸索之后定位到一处代码块,调试的后果十分奇怪。大抵就是:
// 我的页面模板
const template = fn();
// 渲染进去的页面款式
const css = fn();
// 以后拜访页面所用到的 React state
const state = fn();
// 将所有内容由不同的锚点定位,替换到模板中去,每个锚点有且只有一个
const page = template
.replace('css anchor', css)
.replace('state anchor', state)
console.log(template.includes('state anchor'))
// true
console.log(page.includes('state anchor'))
// true
console.log(state.includes('state anchor'))
// false
见鬼了!页面中的描点在替换后还是存在?而后我就在前面又给加了另外一条测试:
const page = template
.replace('css anchor', css)
.replace('state anchor', state)
.replace('state anchor', 'f*** me')
console.log(template.includes('state anchor'))
// true
console.log(page.includes('state anchor'))
// false
console.log(state.includes('state anchor'))
// false
就挺奇怪的,我再替换了一次它就难受了不见了。。接着我顺着描点替换的地位找去,最终发现它在某段文本中的这个地位:
"Use <Space-E> to open explorer" Using Coc-explorer
noremap <space>e :CocCommand explorer<CR>
" Close Coc-explorer if it is the only window
autocmd BufEnter * if (&ft == 'coc-explorer' && winnr("$") == 1) | q | endif
这段是我之前讲 Vim 和 Coc 的文章。重点留神这个 winnr("$")
,因为页面在渲染中做了本义解决,所以拿到的数据其实是 "$"
. 也就是两个引号给替换成 "
了。而我下面用的是 replace 去替换的内容。而在 replace 办法的替换文本中你猜怎么着?$&
代表的是匹配内容自身!所以我的理论替换后果会是:winnr("f*** mequot;)
…
开始解说咯 ~
其实 Javascript 中字符串的 replace 函数,在传入参数为字符串时是有特定的转义字符(变量名)的。比方下面的,如果你写 '$&'
那它就会把你的查找符给替换进去。相似的还有其余一些:
$$
是插入一个 "$"。$&
是插入匹配的子串。$`
是插入以后匹配的子串右边的内容。$'
是插入以后匹配的子串左边的内容。$n
如果第一个参数是 RegExp 对象,并且 n 是个小于 100 的非负整数,那么插入第 n 个括号匹配的字符串。提醒:索引是从 1 开始。如果不存在第 n 个分组,那么将会把匹配到到内容替换为字面量。比方不存在第 3 个分组,就会用“$3”替换匹配到的内容。$<Name>
这里 Name 是一个分组名称。如果在正则表达式中并不存在分组(或者没有匹配),这个变量将被解决为空字符串。只有在反对命名分组捕捉的浏览器中能力应用。
当然你也能够不传字符串传函数进去。这就不开展了,能够到这里认真理解:MDN – String.prototype.replace()
换到理论状况就是因为我插入状态的锚点是个 script 标签,所以 Html 的内容就给截断了。跟跨站攻打(XSS)的原理有点像吧,所以它才只是页面下方呈现了被断开的代码块而注释的显示是失常的。
晓得是什么问题就好修了嘛!本人写一个不会被任何字符串本义的替换函数就好了嘛。
具体怎么写你能够本人想想看 🤣
而后就是开篇的问题,当初晓得答案是什么了吗?
'Hello'.replace('ello', '#$&%')
// 'H#ello%'
好了明天就聊到这儿了~