开发者

Why does decodeURIComponent('%') lock up my browser?

I was just testing something with AJAX and I found that on success if I alert

开发者_JAVA技巧
alert(decodeURI('%'));

or

alert(encodeURIComponent('%'));

the browser errors out with the following code.

$.ajax({
   type: "POST",
   url: "some.php",
   data: "",
   success: function(html){
         alert(decodeURIComponent('%'));
//           alert(decodeURI('%'));
   }
 });

If I use any other string it works just fine.

Is it something that I missed?


Recently a decodeURIComponent in my code tripped over the ampersand % and googling led me to this question.

Here's the function I use to handle % which is shorter than the version of Ilia:

function decodeURIComponentSafe(s) {
    if (!s) {
        return s;
    }
    return decodeURIComponent(s.replace(/%(?![0-9][0-9a-fA-F]+)/g, '%25'));
}

It

  • returns the input value unchanged if input is empty
  • replaces every % NOT followed by a two-digit (hex) number with %25
  • returns the decoded string

It also works with the other samples around here:

  • decodeURIComponentSafe("%%20Visitors") // % Visitors
  • decodeURIComponentSafe("%Directory%20Name%") // %Directory Name%
  • decodeURIComponentSafe("%") // %
  • decodeURIComponentSafe("%1") // %1
  • decodeURIComponentSafe("%3F") // ?


Chrome barfs when trying from the console. It gives an URIError: URI malformed. The % is an escape character, it can't be on its own.


The point is that if you use single % it breaks the logic of decodeURIComponent() function as it expects two-digit data-value followed right after it, for example %20 (space).

There is a hack around. We need to check first if the decodeURIComponent() actually can run on given string and if not return the string as it is.

Example:

function decodeURIComponentSafe(uri, mod) {
    var out = new String(),
        arr,
        i = 0,
        l,
        x;
    typeof mod === "undefined" ? mod = 0 : 0;
    arr = uri.split(/(%(?:d0|d1)%.{2})/);
    for (l = arr.length; i < l; i++) {
        try {
            x = decodeURIComponent(arr[i]);
        } catch (e) {
            x = mod ? arr[i].replace(/%(?!\d+)/g, '%25') : arr[i];
        }
        out += x;
    }
    return out;
}

Running:

decodeURIComponent("%Directory%20Name%")

will result in Uncaught URIError: URI malformed error

while:

decodeURIComponentSafe("%Directory%20Name%") // %Directory%20Name%

will return the initial string.

In case you would want to have a fixed/proper URI and have % turned into %25 you would have to pass 1 as additional parameter to the custom function:

decodeURIComponentSafe("%Directory%20Name%", 1) // "%25Directory%20Name%25"


The problem here is you're trying to decode the %. This is not a valid encoded string. I think you want to encode the % instead.

decodeURI('%') // URIError
encodeURI('%') // '%25'


Unfortunately some of the answers here failed to satisfy my code, so I made an alternative solution. If someone comes looking by with the same problem.

You can use a try...catch block to decode safely. If the string is decodable it will decode, if not, it returns the same string as it is already decoded.

function decodeURIComponentSafely(uri) {
    try {
        return decodeURIComponent(uri)
    } catch(e) {
        console.log('URI Component not decodable: ' + uri)
        return uri
    }
}


Both decodeURI('%') and decodeURIcomponent('%') cannot work because the URL is malformed (a single % is not valid as a url or url component)

Uncaught URIError: URI malformed

encodeURIComponent() works


I had the same issue as OP and found this useful topic. Had to find a way to check if URI string contained percent sign before using decodeURIComponent().

The piece of code from Ilia Rostovtsev works great except for URI which contains encoded characters like %C3 (where percent sign is starting by [A-F]) because the regex used doesn't handle them (only % followed by a decimal).

I replaced the following line:

   x = mod ? arr[i].replace(/%(?!\d+)/g, '%25') : arr[i];

by

   x = mod ? arr[i].replace(/%(?!\d|[ABCDEF]+)/g, '%25') : arr[i];

Now, it is working as the regex will reject %1A to %9F and also %A1 to %F9


The endless-loop or lock up may be due to a bug in jquery.

You can set a breakpoint in jquery at a point which is likely causing the 'lock-up'.

Decode doesn't make sense with just % provided, as percent-encoding is followed by alphanumericals referring to a given character in the ASCII table, and should normally yield an URIError in Opera, Chrome, FF.

Use the browser built in function encodeURI if you are looking for the 'url-encoded' notation of the percent-character:

encodeURI('%')
//>"%25"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜