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

1392

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

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

escape("% +&=");

ИЛИ

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

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

encodeURIComponent("var1=value1&var2=value2");
Адам
источник
111
Стоит отметить, что encodeURIComponent("var1=value1&var2=value2")это не типичный вариант использования. Этот пример закодирует =и &, что, вероятно, не то, что было задумано! encodeURIComponentобычно применяется отдельно только к значению в каждой паре ключ-значение (часть после каждого =).
Тимоти Шилдс
3
тебе нужно что-нибудь сделать с ключом? Что если в нем есть =? (это вообще возможно?)
Мала
3
@Mala Я все еще новичок в веб-программировании в целом, но то, что я использовал в своем ограниченном опыте, заключается в том, чтобы кодировать ключ и значение отдельно, гарантируя, что '=' остается: var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);- Может быть, кто-то другой знает лучший способ.
nedshares
1
@nedshares Я играл с этим, но, насколько я могу судить, ключ, кажется, не закодирован ... по крайней мере, не так. Может быть, против спецификации иметь = в ключе?
Мала
1
Также стоит отметить, что последние реализации JavaScript предоставляют интерфейсы более высокого уровня URL и URLSearchParams для управления URL-адресами и их строками запроса.
Барт Робинсон

Ответы:

1914

побег()

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

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

Поведение:

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

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

Форма шестнадцатеричное для персонажей, чей код блока значение 0xFF или менее, представляет собой последовательность выхода из двух цифр: %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

Arne Evertsson
источник
31
@Francois, в зависимости от принимающего сервера, может некорректно декодировать, как escape кодирует верхние символы ASCII или не-ASCII, такие как: • Например, класс Python FieldStorage не будет правильно декодировать вышеуказанную строку, если закодирован пока escape.
Рэй
22
@Francois escape () кодирует нижние 128 символов ASCII, кроме букв, цифр и *@-_+./, тогда как unescape () является обратным к escape (). Насколько я могу судить, это устаревшие функции, предназначенные для кодирования URL-адресов и все еще реализованные для обратной совместимости. Как правило, их не следует использовать, если они не взаимодействуют с приложением / веб-службой / и т. Д., Предназначенными для них.
Энтони ДиСанти
3
Если, конечно, вы не пытаетесь передать URL как компонент URI, в этом случае вызовите encodeURIComponent.
Том
4
Почему он не обрабатывает одинарные кавычки?
Эрик
11
@Eric Он не кодирует одинарные кавычки, поскольку одинарные кавычки - это полностью допустимый символ, встречающийся в URI ( RFC-3986 ). Проблема возникает, когда вы встраиваете URI в HTML, где одинарная кавычка не является допустимым символом. Из этого следует, что URI также должны быть «закодированы в HTML» (который будет заменен 'на ') перед помещением в документ HTML.
Ли
441

Разница между 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);

Иоганн Эчаваррия
источник
Разве этот браузер не зависит?
Pacerier
4
@bladnman encodeURI и encodeURIComponent должны работать таким образом во всех основных браузерах. Вы можете протестировать приведенный выше код в Chrome и Firefox, так как оба поддерживают console.table. В других браузерах (включая Firefox и Chrome) вы можете использовать следующий код:var arr=[]; for(var i=0;i<256;i++){var char=String.fromCharCode(i); if(encodeURI(char)!==encodeURIComponent(char)) console.log("character: "+char + " | encodeURI: " +encodeURI(char) + " |encodeURIComponent: " + encodeURIComponent(char) ) }
Иоганн Эчаваррия,
1
Я имел в виду @Pacerier :)
Иоганн Эчаваррия
@Pacerier должен быть одинаковым в разных браузерах, если оригинальная спецификация не слишком двусмысленная ... также см. Stackoverflow.com/questions/4407599/…
Кристоф Руссси
2
Я НУЖЕН СДЕЛАТЬ ЭТОТ НЕСКОЛЬКО РАЗ! К сожалению, может поднять только один раз.
Рамазан Полат
46

Я нашел эту статью поучительной: 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!
Damien
источник
11
Статья, на которую вы ссылаетесь, содержит много глупостей. Мне кажется, сам автор не понял, для чего эти функции должным образом используются ...
Кристоф
2
@Christoph Все это выглядит разумно для меня. В частности, я согласен с ним, что encodeURIкажется, что это полезно только в довольно неясном случае и действительно не должно существовать. У меня есть некоторые расхождения во мнениях с ним, но я не вижу в этом ничего откровенного или идиотского. Что именно вы считаете ерундой?
Марк Эмери
1
enctypeАтрибут FORMэлемент определяет тип содержимого , используемый для кодирования набора данных формы для представления на сервер. application / x-www-form-urlencoded Это тип содержимого по умолчанию. Формы, представленные с этим типом содержимого, должны быть закодированы следующим образом: [...] Пробельные символы заменяются на `` + ', а [...] не буквенно-цифровые символы заменяются на `% HH', [...] Ссылка: HTML4 Sepc
cychoi
2
encodeURIComponent ('A + B'). replace (/ \% 20 / g, '+') + '\ n' + decodeURIComponent ("A +% 2B + B" .relace (/ \ + / g, "% 20") ));
Златин Златев
39

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 "";
}
Киранкумар Срипати
источник
5
Это также не делает знак # (фунт / хэш / число), который является% 23.
xr280xr
1
@ xr280xr Что ты имеешь в виду? encodeURIComponent кодирует # в% 23 (может быть, не в 2014 году?)
Дэвид Балажич
38

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

Даниэль Папасян
источник
Если у меня есть URL-адрес, подобный следующему: var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"... и я хочу получить к нему доступ через API Google Ajax, например, так: var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;... тогда я должен использовать escape(url). encodeURI(url)не работает с такими параметрами, как кажется.
Ланс Поллард
15
Вы должны использовать ecnodeURIComponent (url)
Устаман Сангат
2
Все 3 функции имеют свои проблемы. Лучше создать свою собственную функцию, которая делает эту работу.
Джерри Джозеф
17

Небольшая таблица сравнения 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
30thh
источник
12

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

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

Джерри Джозеф
источник
1
Какой отличный ответ (если он совместим с Chrome и Firefox, не делая ошибок)
Ян Bellavance
10

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

Псевдо мазохист
источник
8

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

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

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

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

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

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

Гаурав Тивари
источник
3

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

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

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

veeTrain
источник
2

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

Обратите внимание, что 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"
Майкл
источник
2

Современное переписывание ответа @ 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(для более красивого вывода).

ryanpcmcquen
источник
2

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

скриншот console.table

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


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

скриншот console.table

<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>
akinuri
источник
1

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

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;
};
molokoloco
источник
4
@ChristianVielma escape () устарела, но никогда не ссылается на w3schools.com. см. w3fools.com
Джерри Джозеф
4
@Christian Vielma - Некоторые находят справочный материал по W3Schools быть менее спорным и полезным . Не все согласны с тем, что на W3Schools никогда не следует ссылаться.
DavidRR
2
W3Schools получает плохой рэп. Конечно, они не всегда точны, но опять же я наткнулся на множество постов в блоге, которые также совершенно неверны. Для меня это иногда отличная отправная точка просто для изучения некоторой терминологии, а затем я погружаюсь немного глубже с другими ресурсами. Наиболее важным является то, что один ресурс никогда не должен быть библейским, когда дело доходит до такого рода вещей.
ryandlf
Кажется, @molokoloco написал эту функцию как запасной вариант к версиям, где encodeURIне существует, но escapeсуществует.
SOFe