阅读 240

Koa 依赖的库 encodeurl 和 escape-html

本文为 koa 依赖系列文章,前几篇也可以在站内查看:

  • koa 中依赖的库 parseurl

  • Koa 依赖的库 type-is 和 content-disposition

  • Koa 依赖的库 accepts、content-type 和 cache-content-type

这次看两个字符串相关的库,在 Koa 中都只在 response 中的 redirect 函数内使用到。

encodeurl 用于 redirect 中 Location 的设置,当重定向时,response header 中有 Location 属性,值是一个 Url,在 koa 中此 url 使用 encodeurl 库进行编码,encodeurl 源码如下:

var ENCODE_CHARS_REGEXP = /(?:[^\x21\x25\x26-\x3B\x3D\x3F-\x5B\x5D\x5F\x61-\x7A\x7E]|%(?:[^0-9A-Fa-f]|[0-9A-Fa-f][^0-9A-Fa-f]|$))+/g
var UNMATCHED_SURROGATE_PAIR_REGEXP = /(^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF]([^\uDC00-\uDFFF]|$)/g
var UNMATCHED_SURROGATE_PAIR_REPLACE = '$1\uFFFD$2'
function encodeUrl (url) {
  return String(url)
    .replace(UNMATCHED_SURROGATE_PAIR_REGEXP, UNMATCHED_SURROGATE_PAIR_REPLACE)
    .replace(ENCODE_CHARS_REGEXP, encodeURI)
}复制代码

可以看到 encodeurl 全部代码很少,最终调用的还是 encodeURI,不过在调用之前做了一些处理,这样已经被编码过的数据不会被重复编码,举个例子:

原始 url http://localhost:3001/te st 包含一个空格,此时需要进行编码,encode 之后的 url 变为 http://localhost:3001/te%20st ,此时空格被编码为 %20,如果将新的 url 再进行一次编码,百分号会被编码成 %25,此时编码结果为 http://localhost:3001/te%2520st ,原生的 encodeURI 方法只会对传入的字符串各个字符一一做编码转换,不会去判断是否已经经过了一次编码。作为一个通用的方法 encodeURI 这个逻辑是合理的,但是在 koa 中这个应用场景下已经编码过的 Url 不应该被再次编码,因此此处使用了 encodeurl 中的逻辑。

接下来看 escape-html 库,从名字可以看出这是一个过滤 html 字符串的工具,在浏览器中为了防止 XSS,对于从用户侧接收到的数据都要进行 escape 处理,这里 koa 中也是这个用途。在 redirect 逻辑中有这样一段代码:

if (this.ctx.accepts('html')) {
	url = escape(url)
	this.type = 'text/html; charset=utf-8'
	this.body = `Redirecting to <a href="${url}">${url}</a>.`
	return
}复制代码

这里如果浏览器可以接收 html,koa 会在 body 添加一个 a 标签,这里会把 url 中的信息通过 a 标签渲染到页面上,由于 url 信息可能会包含特殊的 html 字符串,因此此处经过了一次 escape-html 处理,源码如下:

var matchHtmlRegExp = /["'&<>]/

function escapeHtml (string) {
  var str = '' + string
  var match = matchHtmlRegExp.exec(str)

  if (!match) {
    return str
  }

  var escape
  var html = ''
  var index = 0
  var lastIndex = 0

  for (index = match.index; index < str.length; index++) {
    switch (str.charCodeAt(index)) {
      case 34: // "
        escape = '&quot;'
        break
      case 38: // &
        escape = '&amp;'
        break
      case 39: // '
        escape = '&#39;'
        break
      case 60: // <
        escape = '&lt;'
        break
      case 62: // >
        escape = '&gt;'
        break
      default:
        continue
    }

    if (lastIndex !== index) {
      html += str.substring(lastIndex, index)
    }

    lastIndex = index + 1
    html += escape
  }

  return lastIndex !== index
    ? html + str.substring(lastIndex, index)
    : html
}复制代码

代码逻辑本身不复杂,这里的匹配表达式为 /["'&<>]/ ,把对应的五个特殊字符替换为安全的字符编码即可。

以上是两个字符串相关库的源码,这次内容很少,可以看出字符串处理离不开正则表达式的灵活应用,在前面 header 相关的库中也能看到很多相关的实践。


作者:丨隋堤倦客丨
链接:https://juejin.cn/post/7030970125331202062


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐