Кодировать URL в JavaScript?

Как безопасно кодировать URL-адрес с помощью JavaScript, чтобы его можно было вставить в строку GET?

var myUrl = "http://example.com/index.html?param=1&anotherParam=2";
var myOtherUrl = "http://example.com/index.html?url=" + myUrl;

Я предполагаю, что вам нужно кодировать myUrl переменная во второй строке?

22 ответа

Решение

Проверьте встроенную функцию encodeURIComponent(str) а также encodeURI(str),
В вашем случае это должно работать:

var myOtherUrl = 
       "http://example.com/index.html?url=" + encodeURIComponent(myUrl);

У вас есть три варианта:

  • escape() не будет кодировать: @*/+

  • encodeURI() не будет кодировать: ~!@#$&*()=:/,;?+'

  • encodeURIComponent() не будет кодировать: ~!*()'

Но в вашем случае, если вы хотите передать URL в GET параметр другой страницы, вы должны использовать escape или же encodeURIComponent, но нет encodeURI,

См. Вопрос "Переполнение стека". Передовая практика: escape или encodeURI / encodeURIComponent для дальнейшего обсуждения.

Придерживаться encodeURIComponent(), Функция encodeURI() не кодирует много символов, имеющих семантическое значение в URL (например, "#", "?" и "&"). escape() устарела и не имеет смысла кодировать символы "+", которые будут интерпретироваться как закодированные пробелы на сервере (и, как указано другими здесь, неправильно кодирует URL-адреса не-ASCII-символов).

Есть хорошее объяснение разницы между encodeURI() а также encodeURIComponent()в другом месте. Если вы хотите что-то кодировать, чтобы его можно было безопасно включить в качестве компонента URI (например, в качестве параметра строки запроса), вы хотите использовать encodeURIComponent(),

Лично я считаю, что многие API хотят заменить " " на "+", поэтому я использую следующее:

encodeURIComponent(value).replace(/%20/g,'+');

escape реализован по-разному в разных браузерах и encodeURI не кодирует большинство символов, которые функционируют в URI (например, # и даже /), - он предназначен для использования с полным URI/URL, не нарушая его.

ПРИМЕЧАНИЕ. Вы используете encodeURIComponent для значений в строке запроса (не для имен полей / значений и определенно не для всего URL). Если вы сделаете это любым другим способом, он не будет кодировать символы, такие как =,?, &, Возможно, оставляя вашу строку запроса открытой.

Пример:

const escapedValue = encodeURIComponent(value).replace(/%20/g,'+');
const url = 'http://example.com/?myKey=' + escapedValue;

Если вы используете JQuery, я бы пошел на $.param метод. Он URL кодирует поля сопоставления объектов со значениями, которые легче читать, чем вызывать метод escape для каждого значения.

$.param({a:"1=2", b:"Test 1"}) // gets a=1%3D2&b=Test+1

Элегантный способ

По моему скромному мнению, самый элегантный способ кодирования параметров запроса - это создать объект с такими параметрами, как

const queryParams = { param1: 'value1', param2: 'value2' }

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

const queryString = new URLSearchParams(queryParams).toString()

как указано в этом ответе: /questions/6528939/kodirovka-stroki-zaprosa-obekta-javascript/6528951#6528951

Я думаю, что теперь, в 2021 году, чтобы быть действительно безопасным, вы всегда должны думать о создании своих URL-адресов с использованием URL()интерфейс . Он сделает большую часть работы за вас. Итак, переходя к вашему коду,

      const baseURL = 'http://example.com/index.html';

const myUrl = new URL(baseURL);
myUrl.searchParams.append('param', '1');
myUrl.searchParams.append('anotherParam', '2');

const myOtherUrl = new URL(baseURL);
myOtherUrl.searchParams.append('url', myUrl.href);

console.log(myUrl.href); // Outputs: http://example.com/index.html?param=1&anotherParam=2
console.log(myOtherUrl.href); // Outputs: http://example.com/index.html?url=http%3A%2F%2Fexample.com%2Findex.html%3Fparam%3D1%26anotherParam%3D2

const params = new URLSearchParams(myOtherUrl.search);

console.log(params.get('url')); // Outputs: http://example.com/index.html?param=1&anotherParam=2

Что-то подобное гарантированно не подведет.

encodeURIComponent() - это путь.

var myOtherUrl = "http://example.com/index.html?url=" + encodeURIComponent(myUrl);

НО вы должны иметь в виду, что есть небольшие отличия от версии PHP urlencode() и, как упоминалось в @CMS, он не будет кодировать каждый символ. Ребята на http://phpjs.org/functions/urlencode/ сделали js эквивалентным phpencode():

function urlencode(str) {
  str = (str + '').toString();

  // Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current
  // PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following.
  return encodeURIComponent(str)
    .replace(/!/g, '%21')
    .replace(/'/g, '%27')
    .replace(/\(/g, '%28')
    .replace(/\)/g, '%29')
    .replace(/\*/g, '%2A')
    .replace(/%20/g, '+');
}

Для кодирования URL, как уже было сказано, у вас есть две функции:

encodeURI()

а также

encodeURIComponent()

Причина обоих заключается в том, что первый сохраняет URL-адрес с риском оставить слишком много вещей без изменений, а второй кодирует все необходимое.

С первым вы можете скопировать недавно экранированный URL в адресную строку (например), и он будет работать. Однако ваши неэкранированные '&' будут мешать разделителям полей, '=' будут влиять на имена и значения полей, а '+' будут выглядеть как пробелы. Но для простых данных, когда вы хотите сохранить природу URL того, что вы избегаете, это работает.

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

Поэтому, если вы можете потратить время, вы всегда хотите использовать encodeURIComponent() - перед добавлением пар имя / значение кодируйте и имя, и значение, используя эту функцию, перед добавлением его в строку запроса.

Мне трудно найти причины для использования encodeURI() - я оставлю это более умным людям.

Что такое кодировка URL:

URL-адрес должен быть закодирован, если в нем есть специальные символы. Например:

console.log(encodeURIComponent('?notEncoded=&+'));

В этом примере мы можем наблюдать, что все символы, кроме строки notEncoded кодируются знаками%. Кодировка URL также называется процентной кодировкой, поскольку она экранирует все специальные символы с помощью%. Затем после этого знака% каждый специальный символ имеет уникальный код

Зачем нам нужна кодировка URL:

Некоторые символы имеют специальное значение в строке URL. Например,? символ обозначает начало строки запроса. Чтобы успешно найти ресурс в сети, необходимо различать, когда символ подразумевается как часть строки или часть структуры url.

Как мы можем добиться кодирования URL в JS:

JS предлагает набор встроенных служебных функций, которые мы можем использовать для простого кодирования URL. Это два удобных варианта:

  1. encodeURIComponent(): Принимает в качестве аргумента компонент URI и возвращает закодированную строку URI.
  2. encodeURI(): Принимает URI в качестве аргумента и возвращает закодированную строку URI.

Пример и предостережения:

Помните, что не следует передавать весь URL (включая схему, например, https://) в encodeURIComponent(), Это может фактически превратить его в не функциональный URL. Например:

// for a whole URI don't use encodeURIComponent it will transform
// the / characters and the URL won't fucntion properly
console.log(encodeURIComponent("http://www.random.com/specials&char.html"));

// instead use encodeURI for whole URL's
console.log(encodeURI("http://www.random.com/specials&char.html"));

Мы можем наблюдать, если мы поместим весь URL в encodeURIComponent что косые черты (/) также преобразуются в специальные символы. Это приведет к тому, что URL больше не будет работать должным образом.

Поэтому (как следует из названия) используйте:

  1. encodeURIComponent на определенной части URL, который вы хотите закодировать.
  2. encodeURI на весь URL, который вы хотите закодировать.

Чтобы избежать двойного кодирования, рекомендуется декодировать URL-адрес перед кодированием (например, если вы имеете дело с введенными пользователем URL-адресами, которые могут быть уже закодированы).

Допустим, у нас есть abc%20xyz 123 в качестве ввода (один пробел уже закодирован):

encodeURI("abc%20xyz 123")            //   wrong: "abc%2520xyz%20123"
encodeURI(decodeURI("abc%20xyz 123")) // correct: "abc%20xyz%20123"

Вы не должны использовать encodeURIComponent() прямо.

Взгляните на RFC3986: Uniform Resource Identifier (URI): Generic Syntax

sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" знак равно

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

Эти зарезервированные символы из определения URI в RFC3986 НЕ экранируются encodeURIComponent().

Веб-документы MDN: encodeURIComponent()

Чтобы быть более строгим при соблюдении RFC 3986 (который резервирует!, ', (,) И *), даже если эти символы не имеют формализованного использования в качестве разделителей URI, можно безопасно использовать следующее:

Используйте функцию MDN Web Docs...

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

Подобные вещи я пробовал с обычным JavaScript

function fixedEncodeURIComponent(str){
     return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
}

Спектакль

Сегодня (2020.06.12) я провожу тест скорости выбранных решений на MacOs HighSierra 10.13.6 в браузерах Chrome 83.0, Safari 13.1, Firefox 77.0. Эти результаты могут быть полезны для массового кодирования URL-адресов.

Выводы

  • encodeURI(B) кажется самым быстрым, но не рекомендуется для url-ов
  • escape (A) - быстрое кросс-браузерное решение
  • решение F, рекомендованное MDN, является средне быстрым
  • решение D самое медленное

Детали

Для решений A B C D E F я провожу два теста

  • для короткого url - 50 символов - можете запустить ЗДЕСЬ
  • для длинного URL - 1M char - вы можете запустить ЗДЕСЬ

function A(url) {
 return escape(url);
}

function B(url) {
 return encodeURI(url);
}

function C(url) {
 return encodeURIComponent(url);
}

function D(url) {
 return new URLSearchParams({url}).toString();
}

function E(url){
     return encodeURIComponent(url).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
}

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



// ----------
// TEST
// ----------

var myUrl = "http://example.com/index.html?param=1&anotherParam=2";

[A,B,C,D,E,F]
  .forEach(f=> console.log(`${f.name} ?url=${f(myUrl).replace(/^url=/,'')}`));
This snippet only presents code of choosen solutions

Примеры результатов для Chrome

У меня ничего не получалось. Я видел только HTML-код страницы входа, возвращаясь на клиентскую сторону с кодом 200. (Сначала 302, но тот же Ajax-запрос, загружающий страницу входа внутри другого Ajax-запроса, который должен был быть перенаправлением, а не простой загрузкой текст страницы входа).

В контроллере входа я добавил эту строку:

Response.Headers["land"] = "login";

И в глобальном обработчике Ajax я сделал это:

$(function () {
    var $document = $(document);
    $document.ajaxSuccess(function (e, response, request) {
        var land = response.getResponseHeader('land');
        var redrUrl = '/login?ReturnUrl=' + encodeURIComponent(window.location);
        if(land) {
            if (land.toString() === 'login') {
                window.location = redrUrl;
            }
        }
    });
});

Теперь у меня нет никаких проблем, и это работает как шарм.

Использовать fixedEncodeURIComponentфункция должна строго соответствовать RFC 3986:

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

Кодировать строку URL

    var url = $(location).attr('href'); // получить текущий URL
    //ИЛИ ЖЕ
    var url = 'folder/index.html?param=#23dd&noob=yes'; // или укажите один

var encodedUrl = encodeURIComponent(url); console.log(encodedUrl); //outputs folder%2Findex.html%3Fparam%3D%2323dd%26noob%3Dyes for more info go http://www.sitepoint.com/jquery-decode-url-string

Вот живая демонстрация encodeURIComponent() а также decodeURIComponent() JS встроенные функции:

<!DOCTYPE html>
<html>
  <head>
    <style>
      textarea{
        width:30%;
        height:100px;
      }
    </style>
    <script>
      // encode string to base64
      function encode()
      {
        var txt = document.getElementById("txt1").value;
        var result = btoa(txt);
        document.getElementById("txt2").value = result;
      }
      // decode base64 back to original string
      function decode()
      {
        var txt = document.getElementById("txt3").value;
        var result = atob(txt);
        document.getElementById("txt4").value = result;
      }
    </script>
  </head>
  <body>
    <div>
      <textarea id="txt1">Some text to decode
      </textarea>
    </div>
    <div>
      <input type="button" id="btnencode" value="Encode" onClick="encode()"/>
    </div>
    <div>
      <textarea id="txt2">
      </textarea>
    </div>
    <br/>
    <div>
      <textarea id="txt3">U29tZSB0ZXh0IHRvIGRlY29kZQ==
      </textarea>
    </div>
    <div>
      <input type="button" id="btndecode" value="Decode" onClick="decode()"/>
    </div>
    <div>
      <textarea id="txt4">
      </textarea>
    </div>
  </body>
</html>

Вы можете использовать библиотеку esapi и кодировать свой URL, используя функцию ниже. Функция переносит то, что "/" не теряется для кодирования, в то время как остальная часть текстового содержимого кодируется:

function encodeUrl(url)
{
    String arr[] = url.split("/");
    String encodedUrl = "";
    for(int i = 0; i<arr.length; i++)
    {
        encodedUrl = encodedUrl + ESAPI.encoder().encodeForHTML(ESAPI.encoder().encodeForURL(arr[i]));
        if(i<arr.length-1) encodedUrl = encodedUrl + "/";
    }
    return url;
}

https://www.owasp.org/index.php/ESAPI_JavaScript_Readme

var myOtherUrl = 
   "http://example.com/index.html?url=" + encodeURIComponent(myUrl).replace(/%20/g,'+');

Не забудьте флаг /g, чтобы заменить все закодированные ' '

Используйте обратную кавычку в ES6 для кодирования URL-адресов

попробуйте это - https://bbbootstrap.com/code/encode-url-javascript-26885283

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

      function urlEncode(text) {
    let encoded = '';
    for (let char of text) {
        encoded += '%' + char.charCodeAt(0).toString(16);
    }
    return encoded;
}
Другие вопросы по тегам