Когда вы должны использовать escape вместо encodeURI / encodeURIComponent?

При кодировании строки запроса для отправки на веб-сервер - когда вы используете escape() и когда вы используете encodeURI() или же encodeURIComponent():

Используйте escape:

escape("% +&=");

ИЛИ ЖЕ

используйте encodeURI() / encodeURIComponent()

encodeURI("http://www.google.com?var1=value1&var2=value2");

encodeURIComponent("var1=value1&var2=value2");

16 ответов

Решение

побег()

Не используйте это!escape() определено в разделе В.2.1.2 побег, а во вводном тексте Приложения В говорится:

... Все языковые функции и поведения, указанные в этом приложении, имеют одну или несколько нежелательных характеристик, и при отсутствии устаревшего использования будут удалены из этой спецификации....
... Программисты не должны использовать или предполагать существование этих функций и поведения при написании нового кода ECMAScript....

Поведение:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape

Специальные символы кодируются за исключением: @*_+-./

Шестнадцатеричная форма для символов, значение кодовой единицы которых равно 0xFF или меньше, представляет собой двузначную escape-последовательность: %xx,

Для символов с большей единицей кода используется четырехзначный формат %uxxxx используется. Это не разрешено в строке запроса (как определено в RFC3986):

query       = *( pchar / "/" / "?" )
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded   = "%" HEXDIG HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
              / "*" / "+" / "," / ";" / "="

Знак процента разрешен только в том случае, если за ним сразу следуют две шестнадцатеричные цифры, за процентами следует u не допускается.

encodeURI ()

Используйте encodeURI, когда вы хотите рабочий URL. Сделайте этот звонок:

encodeURI("http://www.example.org/a file with spaces.html")

получить:

http://www.example.org/a%20file%20with%20spaces.html

Не вызывайте encodeURIComponent, так как это уничтожит URL и вернет

http%3A%2F%2Fwww.example.org%2Fa%20file%20with%20spaces.html

encodeURIComponent()

Используйте encodeURIComponent, когда вы хотите закодировать значение параметра URL.

var p1 = encodeURIComponent("http://example.org/?a=12&b=55")

Затем вы можете создать нужный вам URL:

var url = "http://example.net/?param1=" + p1 + "&param2=99";

И вы получите этот полный URL:

http://example.net/?param1=http%3A%2F%2Fexample.org%2F%Ffa%3D12%26b%3D55&param2=99

Обратите внимание, что encodeURIComponent не выходит за пределы ' персонаж. Распространенной ошибкой является использование ее для создания атрибутов HTML, таких как href='MyUrl', который может пострадать от ошибки инъекции. Если вы строите HTML из строк, либо используйте " вместо ' для кавычек атрибутов, или добавить дополнительный уровень кодирования (' может быть закодировано как%27).

Для получения дополнительной информации об этом типе кодировки вы можете проверить: http://en.wikipedia.org/wiki/Percent-encoding

Разница между encodeURI() а также encodeURIComponent() это ровно 11 символов, закодированных с помощью encodeURIComponent, но не с помощью encodeURI:

Таблица с десятью различиями между encodeURI и encodeURIComponent

Я сгенерировал эту таблицу легко с console.table в Google Chrome с этим кодом:

var arr = [];
for(var i=0;i<256;i++) {
  var char=String.fromCharCode(i);
  if(encodeURI(char)!==encodeURIComponent(char)) {
    arr.push({
      character:char,
      encodeURI:encodeURI(char),
      encodeURIComponent:encodeURIComponent(char)
    });
  }
}
console.table(arr);

Я нашел эту статью поучительной: Javascript Madness: запрос разбора строк

Я обнаружил это, когда пытался понять, почему decodeURIComponent неправильно декодирует "+". Вот выдержка:

String:                         "A + B"
Expected Query String Encoding: "A+%2B+B"
escape("A + B") =               "A%20+%20B"     Wrong!
encodeURI("A + B") =            "A%20+%20B"     Wrong!
encodeURIComponent("A + B") =   "A%20%2B%20B"   Acceptable, but strange

Encoded String:                 "A+%2B+B"
Expected Decoding:              "A + B"
unescape("A+%2B+B") =           "A+++B"       Wrong!
decodeURI("A+%2B+B") =          "A+++B"       Wrong!
decodeURIComponent("A+%2B+B") = "A+++B"       Wrong!

encodeURIComponent не кодирует -_.!~*'(), вызывая проблему при публикации данных на PHP в XML-строке.

Например:
<xml><text x="100" y="150" value="It's a value with single quote" /> </xml>

Общий побег с encodeURI
%3Cxml%3E%3Ctext%20x=%22100%22%20y=%22150%22%20value=%22It's%20a%20value%20with%20single%20quote%22%20/%3E%20%3C/xml%3E

Как видите, одинарные кавычки не закодированы. Чтобы решить проблему, я создал две функции для решения проблемы в своем проекте для URL кодирования:

function encodeData(s:String):String{
    return encodeURIComponent(s).replace(/\-/g, "%2D").replace(/\_/g, "%5F").replace(/\./g, "%2E").replace(/\!/g, "%21").replace(/\~/g, "%7E").replace(/\*/g, "%2A").replace(/\'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29");
}

Для декодирования URL:

function decodeData(s:String):String{
    try{
        return decodeURIComponent(s.replace(/\%2D/g, "-").replace(/\%5F/g, "_").replace(/\%2E/g, ".").replace(/\%21/g, "!").replace(/\%7E/g, "~").replace(/\%2A/g, "*").replace(/\%27/g, "'").replace(/\%28/g, "(").replace(/\%29/g, ")"));
    }catch (e:Error) {
    }
    return "";
}

encodeURI() - функция escape() предназначена для экранирования JavaScript, а не HTTP.

Небольшая таблица сравнения Java против JavaScript против PHP.

1. Java URLEncoder.encode (using UTF8 charset)
2. JavaScript encodeURIComponent
3. JavaScript escape
4. PHP urlencode
5. PHP rawurlencode

char   JAVA JavaScript --PHP---
[ ]     +    %20  %20  +    %20
[!]     %21  !    %21  %21  %21
[*]     *    *    *    %2A  %2A
[']     %27  '    %27  %27  %27 
[(]     %28  (    %28  %28  %28
[)]     %29  )    %29  %29  %29
[;]     %3B  %3B  %3B  %3B  %3B
[:]     %3A  %3A  %3A  %3A  %3A
[@]     %40  %40  @    %40  %40
[&]     %26  %26  %26  %26  %26
[=]     %3D  %3D  %3D  %3D  %3D
[+]     %2B  %2B  +    %2B  %2B
[$]     %24  %24  %24  %24  %24
[,]     %2C  %2C  %2C  %2C  %2C
[/]     %2F  %2F  /    %2F  %2F
[?]     %3F  %3F  %3F  %3F  %3F
[#]     %23  %23  %23  %23  %23
[[]     %5B  %5B  %5B  %5B  %5B
[]]     %5D  %5D  %5D  %5D  %5D
----------------------------------------
[~]     %7E  ~    %7E  %7E  ~
[-]     -    -    -    -    -
[_]     _    _    _    _    _
[%]     %25  %25  %25  %25  %25
[\]     %5C  %5C  %5C  %5C  %5C
----------------------------------------
char  -JAVA-  --JavaScript--  -----PHP------
[ä]   %C3%A4  %C3%A4  %E4     %C3%A4  %C3%A4
[ф]   %D1%84  %D1%84  %u0444  %D1%84  %D1%84

Я рекомендую не использовать один из этих методов как есть. Напишите свою собственную функцию, которая делает правильные вещи.

MDN привел хороший пример кодирования URL, показанный ниже.

var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''" + encodeRFC5987ValueChars(fileName);

console.log(header); 
// logs "Content-Disposition: attachment; filename*=UTF-8''my%20file%282%29.txt"


function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987, 
            //  so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

Для целей кодирования javascript предоставил три встроенные функции -

  1. escape () - не кодирует @*/+Этот метод считается устаревшим после ECMA 3, поэтому его следует избегать.

  2. encodeURI () - не кодирует ~!@#$&*()=:/,;?+'Предполагается, что URI является полным URI, поэтому не кодирует зарезервированные символы, которые имеют особое значение в URI. Этот метод используется, когда целью является преобразование полного URL-адреса вместо некоторого специального сегмента URL-адреса. Пример - encodeURI('http://stackru.com');даст - http://stackru.com/

  3. encodeURIComponent() - не кодирует - _ . ! ~ * ' ( )Эта функция кодирует компонент универсального идентификатора ресурса (URI), заменяя каждый экземпляр определенных символов одной, двумя, тремя или четырьмя escape-последовательностями, представляющими кодировку UTF-8 символа. Этот метод должен использоваться для преобразования компонента URL. Например, необходимо добавить некоторый пользовательский ввод. Пример - encodeURI('http://stackru.com');даст - http%3A%2F%2Fstackru.com

Все это кодирование выполняется в UTF 8, т.е. символы будут преобразованы в формат UTF-8.

encodeURIComponent отличается от encodeURI тем, что он кодирует зарезервированные символы и номер знака # encodeURI.

Также помните, что все они кодируют разные наборы символов, и выберите тот, который вам нужен. encodeURI() кодирует меньше символов, чем encodeURIComponent(), который кодирует меньше (и также отличается от точки Дэннипа) символов, чем escape().

Вдохновленный столом Иоганна, я решил расширить стол. Я хотел посмотреть, какие символы ASCII кодируются.

var ascii = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";

var encoded = [];

ascii.split("").forEach(function (char) {
    var obj = { char };
    if (char != encodeURI(char))
        obj.encodeURI = encodeURI(char);
    if (char != encodeURIComponent(char))
        obj.encodeURIComponent = encodeURIComponent(char);
    if (obj.encodeURI || obj.encodeURIComponent)
        encoded.push(obj);
});

console.table(encoded);

Таблица показывает только закодированные символы. Пустые ячейки означают, что исходные и закодированные символы совпадают.


Просто чтобы быть лишним, я добавляю еще одну таблицу для urlencode() против rawurlencode(), Кажется, единственная разница заключается в кодировке пробела.

<script>
<?php
$ascii = str_split(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 1);
$encoded = [];
foreach ($ascii as $char) {
    $obj = ["char" => $char];
    if ($char != urlencode($char))
        $obj["urlencode"] = urlencode($char);
    if ($char != rawurlencode($char))
        $obj["rawurlencode"] = rawurlencode($char);
    if (isset($obj["rawurlencode"]) || isset($obj["rawurlencode"]))
        $encoded[] = $obj;
}
echo "var encoded = " . json_encode($encoded) . ";";
?>
console.table(encoded);
</script>

Просто попробуй encodeURI() а также encodeURIComponent() сами...

console.log(encodeURIComponent('@#$%^&*'));

Вход: @#$%^&*. Выход:%40%23%24%25%5E%26*. Итак, подождите, что случилось с*? Почему это не было обращено? TL; DR: вы действительно хотите fixedEncodeURIComponent() а также fixedEncodeURI(). Длинная история...

Когда использовать encodeURI()? Никогда. encodeURI()не соответствует RFC3986 в отношении кодирования скобок. ИспользоватьfixedEncodeURI(), как определено и дополнительно объясняется в документации MDN encodeURI()...

function fixedEncodeURI(str) { return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']'); }

Когда использовать encodeURIComponent()? Никогда. encodeURIComponent() не соответствует RFC3986 в отношении кодирования: !'()*. ИспользоватьfixedEncodeURIComponent(), как определено и более подробно описано в документации MDN encodeURIComponent()...

function fixedEncodeURIComponent(str) { return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { return '%' + c.charCodeAt(0).toString(16); }); }

Тогда вы можете использовать fixedEncodeURI() для кодирования одной части URL, тогда как fixedEncodeURIComponent()будет кодировать части URL и соединители; или простоfixedEncodeURI() не будет кодировать +@?=:#;,$& (как & а также + являются распространенными операторами URL), но fixedEncodeURIComponent() будем.

Принятый ответ хорош. Чтобы продлить на последнюю часть:

Обратите внимание, что encodeURIComponent не экранирует символ '. Распространенной ошибкой является использование ее для создания атрибутов html, таких как href='MyUrl', что может привести к ошибке внедрения. Если вы строите html из строк, либо используйте "вместо" для кавычек атрибутов, либо добавьте дополнительный уровень кодирования ("может быть закодировано как%27).

Если вы хотите быть в безопасности, процентное кодирование незарезервированных символов также должно быть закодировано.

Вы можете использовать этот метод, чтобы избежать их (источник Mozilla)

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}

// fixedEncodeURIComponent("'") --> "%27"

Я обнаружил, что экспериментирование с различными методами является хорошей проверкой работоспособности даже после того, как они хорошо разбираются в том, каковы их различные применения и возможности.

С этой целью я нашел этот сайт чрезвычайно полезным, чтобы подтвердить мои подозрения, что я что-то делаю надлежащим образом. Это также оказалось полезным для декодирования строки encodeURIComponent, которую может быть довольно сложно интерпретировать. Отличная закладка, чтобы иметь:

http://www.the-art-of-web.com/javascript/escape/

Современное переписывание ответа @johann-echavarria:

console.log(
    Array(256)
        .fill()
        .map((ignore, i) => String.fromCharCode(i))
        .filter(
            (char) =>
                encodeURI(char) !== encodeURIComponent(char)
                    ? {
                          character: char,
                          encodeURI: encodeURI(char),
                          encodeURIComponent: encodeURIComponent(char)
                      }
                    : false
        )
)

Или, если вы можете использовать таблицу, заменить console.log с console.table (для более красивого выхода).

У меня есть эта функция...

var escapeURIparam = function(url) {
    if (encodeURIComponent) url = encodeURIComponent(url);
    else if (encodeURI) url = encodeURI(url);
    else url = escape(url);
    url = url.replace(/\+/g, '%2B'); // Force the replacement of "+"
    return url;
};

Короткий ответ

для данных, предназначенных только для анализа JavaScript, используйте , для всего остального используйте encodeURIComponent()

encodeURI и encodeURIComponent

и делают то же самое: они URL-кодируют строку. Однако есть важное отличие: соблюдает структуру URI, но не соблюдает. В большинстве случаев вы не заметите разницы, но когда передаваемый вами аргумент является допустимым URI, некоторые его символы не кодируются, игнорируется структура URI переданного аргумента и кодируются все недопустимые символы. имеют особое значение в URI:

      console.log(encodeURIComponent("Some Example Text"),encodeURI("Some Example Text"));//==>Some%20Example%20Text Some%20Example%20Text
console.log(encodeURIComponent("https://example.com/äöü?param1=content"),encodeURI("https://example.com/äöü?param1=content"));

В приведенном выше примере вы можете ясно видеть, как ведет себя так же, как если бы структура URI не указана, но когда она задана, символы, соответствующие структуре URI, пропускаются, а игнорируются. В большинстве случаев вам нужен encodeURIComponent. Я не могу придумать ни одного случая использования, где encodeURI является лучшим выбором. Если у вас есть пользовательские данные, лучше сделать:

      var url="https://example.com/upload?input="+encodeURIComponent(user_input);

вместо:

      var url=encodeURI("https://example.com/upload?input="+user_input)

потому что пользователь может вставить данные, повреждающие URI (случайно или злонамеренно (хотя предотвращение атак на стороне клиента в любом случае является плохой идеей) или потому, что злоумышленник сказал ему это), например:

      upload_data?second_parameter=unintended_content

который будет правильно закодирован в примере 1, но будет генерировать ошибочные или даже вредоносные URI в примере 2.

ОБА МЕТОДА ВЫДАЮТ ОШИБКУ, ЕСЛИ В ПЕРЕДАВАЕМОЙ СТРОКЕ НАХОДИТСЯ ЕДИНСТВЕННЫЙ ЗАМЕНИТЕЛЬ (0xD800-0xDFFFF).

побег

Несмотря на то, что может показаться, что он URI-кодирует строку, на самом деле он переводит ее в формат, специфичный для JavaScript. Когда только символы в диапазоне ( 0x00-0x7F) закодированы, он ведет себя так же, как (не encodeURI, поскольку он игнорирует структуру URI так же, как это делает encodeURIComponent), за исключением трех специальных символов, которые он не кодирует, даже если они могут иметь особое значение в URI ( @+/). Поведение отличается для кодовых точек выше 0x7F :

переводит это в%uXXXXкогда кодовая точка превышает 0xFF, для кодовых точек в диапазоне 0x80-0xFF преобразует ее в%XX

URL-кодирует его регулярно и выдаетURIErrorдля одиноких суррогатных матерей, вот почему escape()это более надежный метод.

      //0x00-0x7F
console.log(escape("Some Example Text"),encodeURIComponent("Some Example Text")); //==> Some%20Example%20Text Some%20Example%20Text
//Special Characters
console.log(escape("@+/"),encodeURIComponent("@+/"))//==>@+/ %40%2B%2F
//Above 0x7F
console.log(escape(String.fromCodePoint(0x1234)),encodeURIComponent(String.fromCodePoint(0x1234)));//==> %u1234 %E1%88%B4
//2 Valid Surrogates
console.log(escape(""),encodeURIComponent(""));//==> %uD83D%uDE02 %F0%9F%98%82
//Lone Surrogate(0xD800-0xDFFF)
console.log(escape(String.fromCodePoint(0xD800)))//==> %uD800
encodeURIComponent(String.fromCodePoint(0xD800))//URIError

Также примечательно, что escape устарел, но поддерживается всеми основными браузерами (даже IE, хотя я не думаю, что кто-то его больше использует), и нет никаких причин, по которым поддержка может быть прекращена в будущем.

Когда использовать encodeURIComponent, а когда использовать escape?

Для данных, предназначенных только для анализа JavaScript (например, в хеше URI), используйтеescape, для всего остального используйтеencodeURIComponent(и почти никогда не используюencodeURI)

О декодировании

независимо от того, какой из двух реальных вариантов вы выберете, вам необходимо использовать правильный метод декодирования:

      encodeURIComponent ==> decodeURIComponent
escape ==> unescape

Если вы не знаете, как была закодирована строка, используйте следующую функцию для ее автоматического обнаружения (ненадежно/ошибочно, когда символы в диапазоне 0x80-0xFF закодированы с помощью escape, и вместе с ней не кодируются символы >0xFF, надежно в большинстве случаев). другие случаи):

      decode=function(text){return (text.includes("%u")?unescape(text):decodeURIComponent(text))}
Другие вопросы по тегам