Коли ви повинні використовувати escape замість encodeURI / encodeURIComponent?


1392

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

Використовуйте втечу:

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);- Можливо, хтось інший знає кращий спосіб.
недрес

1
@nedshares Я грав з цим, але, наскільки я можу сказати, ключ, здається, не закодований ... принаймні, не таким же чином. Можливо, проти спекуляції мати ключ = =?
Мала

1
Також варто зазначити, що останні впровадження JavaScript надають інтерфейси більш високого рівня URL та URLSearchParams для управління URL-адресами та їх рядками запитів.
Барт Робінсон

Відповіді:


1914

Втеча()

Не використовуйте його! escape()визначено в розділі B.2.1.2 аварійного виклику, а вступний текст Додатку B говорить:

... Усі мовні особливості та поведінка, зазначені в цьому додатку, мають одну або декілька небажаних характеристик, і за відсутності застарілого використання буде вилучено з цієї специфікації. ...
... Програмісти не повинні використовувати або припускати існування цих особливостей і поведінки під час написання нового коду 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


31
@Francois, залежно від приймаючого сервера, він може неправильно розшифрувати, як escape кодує верхні символи ASCII або non-ASCII, такі як: âầẩẫấậêềểễếệ Наприклад, клас FieldStorage Python не розшифрує вищезазначений рядок належним чином, якщо зашифрований бай-біг.
Рей

22
@Francois escape () кодує нижні 128 символів ASCII, за винятком літер, цифр та *@-_+./, тоді як unescape () - зворотний параметр escape (). Наскільки я можу сказати, вони є застарілими функціями, розробленими для кодування URL-адрес і реалізуються лише для зворотної сумісності. Як правило, їх не слід використовувати, якщо взаємодія з додатком / веб-службою / тощо не призначена для них.
Ентоні Дісанті

3
Якщо, звичайно, ви намагаєтеся передати URL як компонент URI, тоді виклик encodeURIComponent.
tom

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) ) }
Johann Echavarria

1
Я мав на увазі @Pacerier :)
Йоганн Ехаваррія

@Pacerier має бути однаковим у різних браузерах, якщо оригінал не надто неоднозначний ... також дивіться stackoverflow.com/questions/4407599/…
Крістоф Руссі

2
Я ПОТРІБНУВАТИ ЦЕ РІЗНІ ЧАСИ! На жаль, можна винести лише один раз.
Рамазан Полат

46

Ця стаття виявила мене просвітницькою: Божевілля Javascript: Розбір рядків запитів

Я виявив це, коли я намагався підкреслити і чому 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!

11
Стаття, на яку ви посилаєтесь, містить багато дурниць. Мені здається, сам автор не зрозумів, для чого правильно використовуються функції ...
Крістоф

2
@Christoph Це все мені здається розумним. Зокрема, я погоджуюся з ним, що encodeURIздається, що це корисно лише у досить незрозумілому крайовому випадку, і справді його не потрібно існувати. У мене є деякі відмінності думок з ним, але я не бачу нічого прямого помилкового чи ідіотичного. Що саме, на вашу думку, є дурницею?
Марк Амері

1
enctypeАтрибут FORMелемент визначає тип вмісту , який використовується для кодування набору даних форми для подання на сервер. application / x-www-form-urlencoded Це тип вмісту за замовчуванням. Форми, подані з цим типом вмісту, повинні бути закодовані наступним чином: [...] Пробіли символів замінюються на `` + ', а [...] Не алфавітно-цифрові символи замінюються на'% HH ', [...] Ref: HTML4 Sepc
cychoi

2
encodeURIComponent ('A + B'). Замінити (/ \% 20 / g, '+') + '\ n' + декодуватиURIComponent ("A +% 2B + B" .замінити (/ \ + / 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)
Ustaman Sangat

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

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
яка чудова відповідь (якщо вона сумісна через хромований край та firefox, не роблячи жодних помилок)
yan 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), замінюючи кожен екземпляр певних символів одним, двома, трьома чи чотирма послідовностями, що представляють собою кодування UTF-8 символу. Цей метод слід використовувати для перетворення компонента URL. Наприклад, потрібно ввести деякі дані користувача Приклад - encodeURIComponent('http://stackoverflow.com'); дасть - http% 3A% 2F% 2Fstackoverflow.com

Все це кодування виконується в UTF 8, тобто символи будуть перетворені у формат UTF-8.

encodeURIComponent відрізняється від encodeURI тим, що він кодує зарезервовані символи та номер номера # encodeURI


3

Я виявив, що експериментувати з різними методами - це хороша перевірка добросовісності навіть після того, як добре розібратися в тому, якими є різні їхні можливості та можливості.

З цією метою я вважаю цей веб-сайт надзвичайно корисним для підтвердження своїх підозр у тому, що я щось роблю належним чином. Він також виявився корисним для декодування рядка encodeURIComponent'ed, який може бути досить складним для інтерпретації. Відмінна закладка:

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


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(для кращого результату).


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>

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;
};

4
@ChristianVielma escape () застарілий, але ніколи не посилайтеся на w3schools.com. дивіться w3fools.com
Джеррі Джозеф

4
@Christian Vielma - Деякі вважають, що довідковий матеріал у W3Schools є менш суперечливим та корисним . Не всі згодні з тим, що на W3Schools ніколи не слід посилатися.
DavidRR

2
W3Schools отримує поганий реп. Звичайно, вони не завжди точні, але знову ж таки я натрапив на багато публікацій у блозі, що також є неправильним. Для мене це часом чудова відправна точка просто вивчити якусь термінологію, а потім я занурююся трохи глибше з іншими ресурсами. Найголовніше, що єдиний ресурс ніколи не повинен бути біблійним, коли мова йде про подібні речі.
ryandlf

Здається, @molokoloco написав цю функцію як резервну версію до версій, де encodeURIне існує, але escapeіснує.
SOFe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.