Nodejs中注意 encodeURIComponent() 的 URIError: URI malformed

Nodejs中注意 encodeURIComponent() 的 URIError: URI malformed

原以为 encodeURIComponent() 是一个安全的不会抛异常的方法,但是最近日志里面捕获到一个 URIError,来自querystring.js

google了一下,从这段代码的实现,可以复现此异常:

> encodeURIComponent(String.fromCharCode(0xDFFF))
URIError: URI malformed
    at repl:1:2
    at REPLServer.eval (repl.js:80:21)
    at Interface.<anonymous> (repl.js:182:12)
    at Interface.emit (events.js:67:17)
    at Interface._onLine (readline.js:162:10)
    at Interface._line (readline.js:426:8)
    at Interface._ttyWrite (readline.js:603:14)
    at ReadStream.<anonymous> (readline.js:82:12)
    at ReadStream.emit (events.js:88:20)
    at ReadStream._emitKey (tty.js:327:10)

现在还没解决的疑问,是这种数据是如何传递过去的。


7 回复

Node.js 中注意 encodeURIComponent()URIError: URI malformed

在使用 Node.js 进行开发时,encodeURIComponent() 是一个常用的方法来对 URL 进行编码。然而,最近我在日志中捕获到了一个 URIError 异常,这让我意识到这个方法并不是绝对安全的。

问题描述

encodeURIComponent() 方法用于将字符串中的特殊字符转换为统一资源标识符(URI)中允许的格式。然而,如果输入的字符串包含某些特定的字符(例如,UTF-16 编码的代理对),则可能会导致 URIError 异常。

示例代码

以下是一个示例代码,演示了如何触发这个异常:

try {
    const invalidChar = String.fromCharCode(0xDFFF);
    console.log(encodeURIComponent(invalidChar));
} catch (error) {
    console.error(error.message); // 输出: URI malformed
}

在这个例子中,我们尝试对 UTF-16 编码的代理对 0xDFFF 进行编码,这会导致 encodeURIComponent() 抛出 URIError 异常。

原因分析

根据 V8 JavaScript 引擎的源代码,encodeURIComponent() 在处理某些特定的 UTF-16 代理对时会抛出异常。具体来说,当输入字符串包含 Unicode 高代理字符(如 0xDFFF)时,encodeURIComponent() 无法正确处理这些字符,从而导致异常。

解决方案

为了防止这种情况发生,可以在调用 encodeURIComponent() 之前进行一些预处理,以确保输入字符串不包含非法字符。例如,可以过滤掉这些非法字符:

function safeEncodeURIComponent(str) {
    return encodeURIComponent(str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, ''));
}

try {
    const invalidChar = String.fromCharCode(0xDFFF);
    console.log(safeEncodeURIComponent(invalidChar)); // 输出: %EF%BF%BD
} catch (error) {
    console.error(error.message);
}

在这个解决方案中,我们定义了一个 safeEncodeURIComponent 函数,该函数首先使用正则表达式过滤掉非法的 UTF-16 代理对,然后再进行编码。

结论

虽然 encodeURIComponent() 是一个强大的工具,但在处理特殊字符时需要小心。通过预处理输入字符串并过滤掉非法字符,可以避免 URIError 异常的发生。希望这个示例能帮助你更好地理解和处理这个问题。


昨天无意间捕捉到了这个错误:

URIError: URI malformed
    at f:\nodeclub\nodeclub\node_modules\express\node_modules\connect\lib\middleware\static.js:119:14
    at Object.static [as handle] (f:\nodeclub\nodeclub\node_modules\express\node_modules\connect\lib\middleware\static.j
s:60:5)
    at next (f:\nodeclub\nodeclub\node_modules\express\node_modules\connect\lib\http.js:204:15)
    at f:\nodeclub\nodeclub\node_modules\express\node_modules\connect\lib\middleware\csrf.js:80:37
    at Object.handle (f:\nodeclub\nodeclub\app.js:39:5)
    at next (f:\nodeclub\nodeclub\node_modules\express\node_modules\connect\lib\http.js:204:15)
    at f:\nodeclub\nodeclub\controllers\sign.js:280:14
    at f:\nodeclub\nodeclub\controllers\message.js:215:12
    at f:\nodeclub\nodeclub\node_modules\mongoose\lib\utils.js:408:16
    at [object Object].<anonymous> (f:\nodeclub\nodeclub\node_modules\mongoose\node_modules\mongodb\lib\mongodb\collecti
on.js:531:7)

不知道怎么出来的,后来再试,无法复现

我也遇到了 先mark一下。

cookie0.0.4会有此问题,我提交了一个pull request,估计不会被接受。https://github.com/shtylman/node-cookie/pull/8

原来已经被合并了。。。

我这边是因为 % 引起的 decodeURIComponent("%") ----->Uncaught URIError: URI malformed decodeURIComponent("%25") ----->%

在 Node.js 中使用 encodeURIComponent() 函数时,可能会遇到 URIError: URI malformed 异常。这个错误通常是因为尝试对一些非法字符进行编码。

原因

encodeURIComponent() 不能对所有 Unicode 字符进行编码。例如,0xDFFF 这个字符就是非法的,因为它属于 UTF-16 编码中的代理对的一部分,但本身不是一个合法的字符。因此,当 encodeURIComponent() 尝试对其进行编码时,会抛出 URIError: URI malformed 异常。

示例代码

try {
    const invalidChar = String.fromCharCode(0xDFFF);
    console.log(encodeURIComponent(invalidChar)); // 抛出 URIError
} catch (error) {
    console.error(error.message); // 输出 "URI malformed"
}

解决方案

如果你需要处理这种非法字符,可以在调用 encodeURIComponent() 之前先过滤掉这些非法字符。一种简单的方法是检查字符的码点,并跳过那些非法的字符:

function safeEncodeURIComponent(str) {
    return str.split('').map(char => {
        const codePoint = char.codePointAt(0);
        if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
            // 跳过非法的代理对字符
            return '';
        }
        return char;
    }).join('').replace(/[^\0-\uFFFF]/g, '');
}

const invalidChar = String.fromCharCode(0xDFFF);
console.log(safeEncodeURIComponent(invalidChar)); // 输出 "%EF%BF%BD"

解释

  • safeEncodeURIComponent 函数将字符串拆分为字符数组,然后逐个检查每个字符的码点。
  • 如果字符的码点位于代理对范围内(即 0xD8000xDFFF),则跳过该字符。
  • 最后,将剩余的字符重新组合成字符串并进行编码。

通过这种方式,你可以避免在 encodeURIComponent() 中出现 URIError: URI malformed 异常。

回到顶部