JavaScript解码遇Uncaught URIError: URI malformed错误的解决
Hey there, let's break down why that third name is causing issues and fix it up!
问题回顾
你这段JavaScript循环用来解码persons数组中的姓名:
for(var idxT in persons){ var name = persons[idxT]; name = decodeURIComponent(escape(name)); players[idxT] = name; } //endFor
前两个姓名解码正常,但处理Ant脙nio Nunes(实际应为带特殊字符的Antônio Nunes)时,控制台抛出Uncaught URIError: URI malformed错误,且这些姓名此前是通过PHP的utf8_encode函数编码的,问题出在乱码的特殊字符上。
问题根源
你当前使用的decodeURIComponent(escape(name))是早期处理UTF-8字符串的一种 hack 方式,但它的局限性很明显:当字符串中包含无效的URI编码字节序列(比如utf8_encode后被错误解析的乱码字符)时,decodeURIComponent会因为无法识别合法的UTF-8序列而抛出错误。
具体来说,Ant脙nio里的脙其实是UTF-8字节0xC3(对应ô的一部分)被当作ISO-8859-1解析后的结果,escape处理它会生成%E8%84%92,而这个序列并不是合法的UTF-8编码,自然会触发解码错误。
解决方案
方案1:从根源避免编码问题(优先推荐)
如果可以调整PHP端的代码,不要用utf8_encode单独处理字符串,而是直接用json_encode输出整个数组。JSON会自动处理UTF-8编码,JS端解析后能直接拿到正确的字符串:
PHP端代码:
// 直接输出JSON格式的persons数组 echo json_encode($persons);
JS端代码:
// 解析PHP输出的JSON,直接得到正确的UTF-8字符串 const persons = JSON.parse(yourPhpResponse); for (const idxT in persons) { players[idxT] = persons[idxT]; }
这种方法完全绕过了手动解码的问题,是最稳妥的解决方案。
方案2:修复JS端的解码逻辑(无法修改PHP时使用)
如果不能调整PHP代码,我们可以通过字节级的转换来还原正确的UTF-8字符串,同时用try-catch避免单个错误中断整个循环:
首先定义一个专门的解码函数:
function decodeUtf8FromIso(str) { // 将乱码字符串转回原始的UTF-8字节(按ISO-8859-1编码) const bytes = new Uint8Array(str.length); for (let i = 0; i < str.length; i++) { bytes[i] = str.charCodeAt(i); } // 用UTF-8解码字节序列,得到正确的字符串 return new TextDecoder('utf-8').decode(bytes); }
然后修改你的循环:
for (const idxT in persons) { let name = persons[idxT]; try { // 先尝试原方法,处理正常的字符串 name = decodeURIComponent(escape(name)); } catch (e) { // 解码失败时,用备用方法处理特殊字符 name = decodeUtf8FromIso(name); } players[idxT] = name; }
这个方法会先尝试原有的解码逻辑,遇到错误时再用字节转换的方式还原正确的姓名,确保整个循环能完成所有元素的处理。
内容的提问来源于stack exchange,提问作者user9324524

