Как безопасно закодировать URL-адрес с помощью JavaScript, чтобы его можно было поместить в строку GET?
var myUrl = "http://example.com/index.html?param=1&anotherParam=2";
var myOtherUrl = "http://example.com/index.html?url = " + myUrl;
Я предполагаю, что вам нужно закодировать переменную myUrl во второй строке?
Вы можете использовать этот инструмент здесь: phillihp.com/toolz/url-encode-decode
См. Функция urlencode JavaScript.
encodeURIComponent ()



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Обратите внимание на встроенную функцию encodeURIComponent (str) и encodeURI (str).
В вашем случае это должно сработать:
var myOtherUrl =
"http://example.com/index.html?url = " + encodeURIComponent(myUrl);
Как насчет добавления объяснения, которое дал @cms? escape также является допустимым вариантом.
согласно @CMS encodeURI не совсем безопасен для кодирования URL.
@AnaelFavre, потому что он предназначен для кодирования всего URL-адреса, что не позволяет использовать такие символы, как :, /, @ и т. д. Эти 2 метода нельзя использовать взаимозаменяемо, вы должны знать, что кодируете, чтобы использовать правильный метод.
См. Также developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… и developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….
Как уже упоминалось, в другом ответе на этой странице, этот сайт подробно описывает причину использования этого метода.
@BuuNguyen это не работает для меня. Я все еще вижу значок & as & amp; в моем терминале.
@BuuNguyen: Привет, BuuNguyen, спасибо за полезное решение. пожалуйста, подтвердите меня? Могу ли я использовать метод encodeURIComponent () для кодирования простой строки, потому что в моем приложении я добавляю строковое содержимое непосредственно как значение для запроса строкового ключа, а затем его ведущую проблему XSS. это мой код var mywindow = window .open( "https://" + window.location.host + "center/js/cal.html?context = " + conString + "&date = " + dateString + "&firstName = " + firstName);
@BuuNguyen: Теперь говорится, что &firstName может быть причиной проблемы с XSS. Что мне теперь делать? если я закодирую firstname, то он разрешится или нет? пожалуйста, предложите мне что-нибудь. Ty.
Есть много хороших сайтов, которые позволят вам поиграть с этим: string-io.com - один из них.
Мне пришлось передать номер +39123.. со знаком плюса: encodeURI() работал, но мой бэкэнд его не видел, в то время как encodeURIComponent() преуспел (в angular 8 и asp.net core 3)
У вас есть три варианта:
escape() не кодирует: @*/+
encodeURI() не кодирует: ~!@#$&*()=:/,;?+'
encodeURIComponent() не кодирует: ~!*()'
Но в вашем случае, если вы хотите передать URL в параметр GET другой страницы, вам следует использовать escape или encodeURIComponent, но не encodeURI.
См. Вопрос о переполнении стека Лучшая практика: escape или encodeURI / encodeURIComponent для дальнейшего обсуждения.
Кодировка символов, используемая с escape-символом, является переменной. Придерживайтесь encodeURI и encodeURIComponent, которые используют UTF-8.
Я использую encodeURIComponent и заметил, что он не кодирует вертикальные символы |
@kevzettler - зачем ему это делать? Каналы не имеют семантического значения в URI.
Будь осторожен. Этот escape-код преобразует символы, отличные от ASCII, в escape-последовательности Unicode, такие как %uxxx.
Кто-нибудь использует символы, отличные от ASCII, в URI?
@GiovanniP: люди, которые разрешают вводить немецкие, французские, японские, китайские, арабские символы и передавать эти параметры через GET или POST.
ах, хорошо, я думал, вы говорите о частях домена / пути, не знаю, почему я так подумал.
encodeURIComponent() кодировал #, а encodeURI() - нет!
@fiatjaf Символы, отличные от ASCII, также вполне допустимы в доменах, хотя в системе DNS будет храниться версия ASCII. en.wikipedia.org/wiki/Internationalized_domain_name
ПРИМЕЧАНИЕ. Начиная с версии 1.5 JavaScript escape () устарел. Придерживайтесь либо encodeURI (), либо encodeComponent (). developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Придерживайтесь encodeURIComponent(). Функция encodeURI() не пытается кодировать многие символы, которые имеют семантическую важность в URL-адресах (например, «#», «?» И «&»). escape() устарел и не пытается кодировать символы «+», которые будут интерпретироваться как закодированные пробелы на сервере (и, как указывалось другими здесь, неправильно кодирует URL-адреса символов, отличных от ASCII).
В другом месте есть хороший объяснение разницы между encodeURI() и encodeURIComponent(). Если вы хотите что-то закодировать, чтобы его можно было безопасно включить в качестве компонента URI (например, в качестве параметра строки запроса), вы хотите использовать encodeURIComponent().
У меня ничего не работало. Все, что я видел, - это 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;
}
}
});
});
Теперь у меня нет никаких проблем, и это работает как шарм.
Лучший ответ - использовать encodeURIComponent на значения в строке запроса (и нигде больше).
Однако я обнаружил, что многие API хотят заменить "" на "+", поэтому мне пришлось использовать следующее:
const value = encodeURIComponent(value).replace('%20','+');
const url = 'http://example.com?lang=en&key=' + value
escape по-разному реализован в разных браузерах, и encodeURI не кодирует много символов (например, # и даже /) - он предназначен для использования с полным URI / URL-адресом, не нарушая его, что не очень полезно и не безопасно.
И как @Jochem указывает ниже, вы можете использовать encodeURIComponent() для (каждого) имени папки, но по какой-то причине эти API, похоже, не хотят, чтобы + в именах папок, поэтому простой старый encodeURIComponent отлично работает.
Пример:
const escapedValue = encodeURIComponent(value).replace('%20','+');
const escapedFolder = encodeURIComponent('My Folder'); // no replace
const url = `http://example.com/${escapedFolder}/?myKey=${escapedValue}`;
Обратите внимание, что вам следует заменять% 20 символами + только после первого вопросительного знака (который является частью URL-адреса «запрос»). Допустим, я хочу перейти к http://somedomain/this dir has spaces/info.php?a=this has also spaces. Его следует преобразовать в: http://somedomain/this%20dir%20has%spaces/info.php?a=this%20has%20also%20spaces, но многие реализации позволяют заменять «% 20» в строке запроса на «+». Тем не менее, вы не можете заменить «% 20» на «+» в разделе пути URL-адреса, это приведет к ошибке «Не найдено», если у вас нет каталога с + вместо пробела.
@Jochem Kuijpers, определенно, вы не стали бы помещать "+" в каталог. Я бы применил это только к самим значениям параметров запроса (или ключам, если необходимо), а не ко всему URL-адресу или даже ко всей строке запроса.
Я бы заменил по значению, а не по результату кодирования
@ njzk2, к сожалению, encodeURIComponent('+') даст вам %2B, поэтому вам придется использовать два регулярных выражения ... что, я полагаю, отчасти почему это работает, потому что '+' are '' в конце кодируются по-разному.
Нет причин переводить% 20 в "+". Допустимая escape-последовательность для пространства ASCII -% 20, а не «+», который не упоминается в RFC 3986 (tools.ietf.org/html/rfc3986). «+» использовалось в 1990-х годах; Сейчас он устарел и поддерживается только по устаревшим причинам. Не используйте это.
@xhienne наверняка, это просто то, что я заметил в реальном мире на нескольких API, всегда было бы разумнее использовать encodeURIComponent, когда это работает - было бы неплохо, если бы люди могли придерживаться одного стандарта! И желательно спецификацию RFC.
Независимо от того, это a + или% 20, декодирующий компонент должен знать, как интерпретировать любое значение и создавать пробел. Только спецификации, такие как oauth, требуют закодированных строк в своей спецификации, где это имеет значение.
Я бы посоветовал использовать пакет qs npm
qs.stringify({a:"1=2", b:"Test 1"}); // gets a=1%3D2&b=Test+1
его проще использовать с объектом JS, и он дает вам правильную кодировку URL для всех параметров
Если вы используете jQuery, я бы выбрал метод $.param. Он URL-адрес кодирует поля сопоставления объекта со значениями, которые легче читать, чем вызывать метод escape для каждого значения.
$.param({a:"1=2", b:"Test 1"}) // gets a=1%3D2&b=Test+1
Я думаю, что приведенного примера достаточно. Если вам нужна дополнительная информация о $ .param на api.jquery.com/jquery.param
Практически все используют jQuery, и я чувствую себя более комфортно с этим вместо encoreURIComponent
Подобные вещи я пробовал с обычным javascript
function fixedEncodeURIComponent(str){
return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
}
Кодировать строку URL
var url = $(location).attr('href'); //get current url
//OR
var url = 'folder/index.html?param=#23dd&noob=yes'; //or specify one
var encodedUrl = encodeURIComponent(url);
console.info(encodedUrl);
//outputs folder%2Findex.html%3Fparam%3D%2323dd%26noob%3Dyes
for more info go http://www.sitepoint.com/jquery-decode-url-string
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('!', '%21')
.replace('\'', '%27')
.replace('(', '%28')
.replace(')', '%29')
.replace('*', '%2A')
.replace('%20', '+');
}
Вы можете использовать библиотеку 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;
}
Чтобы предотвратить двойное кодирование, рекомендуется декодировать URL-адрес перед кодированием (например, если вы имеете дело с URL-адресами, введенными пользователем, которые могут быть уже закодированы).
Допустим, у нас есть abc%20xyz 123 в качестве входных данных (один пробел уже закодирован):
encodeURI("abc%20xyz 123") // wrong: "abc%2520xyz%20123"
encodeURI(decodeURI("abc%20xyz 123")) // correct: "abc%20xyz%20123"
Чтобы закодировать URL-адрес, как было сказано ранее, у вас есть две функции:
encodeURI()
и
encodeURIComponent()
Причина, по которой оба существуют, заключается в том, что первый сохраняет URL-адрес с риском оставить без экранирования слишком много вещей, а второй кодирует все необходимое.
С первым вы можете скопировать только что экранированный URL-адрес в адресную строку (например), и он будет работать. Однако ваши неэкранированные символы '&' будут мешать разделителям полей, '=' будут мешать именам и значениям полей, а '+' будут выглядеть как пробелы. Но для простых данных, когда вы хотите сохранить URL-адрес того, что вы экранируете, это работает.
Во-вторых, все, что вам нужно сделать, чтобы убедиться, что ничто в вашей строке не мешает URL-адресу. Он оставляет без экранирования различные неважные символы, так что URL-адрес остается максимально читаемым человеком без каких-либо помех. URL-адрес, закодированный таким образом, больше не будет работать как URL-адрес без его экранирования.
Поэтому, если у вас есть время, вы всегда хотите использовать encodeURIComponent () - перед добавлением пар имя / значение кодируйте как имя, так и значение с помощью этой функции, прежде чем добавлять его в строку запроса.
Мне сложно придумывать причины для использования encodeURI () - я оставлю это умным людям.
URL-адрес должен быть закодирован, если внутри URL-адреса есть специальные символы. Например:
console.info(encodeURIComponent('?notEncoded=&+'));В этом примере мы можем заметить, что все символы, кроме строки notEncoded, закодированы знаками%. Кодировка URL-адреса также известна как процентное кодирование, потому что она экранирует все специальные символы с помощью%. Затем после этого знака% каждый специальный символ имеет уникальный код.
Некоторые символы имеют специальное значение в строке URL-адреса. Например, знак? символ обозначает начало строки запроса. Чтобы успешно найти ресурс в сети, необходимо различать, когда символ подразумевается как часть строки или как часть структуры URL-адреса.
JS предлагает набор встроенных служебных функций, которые мы можем использовать для простого кодирования URL-адресов. Это два удобных варианта:
encodeURIComponent(): принимает компонент URI в качестве аргумента и возвращает закодированную строку URI.encodeURI(): принимает URI в качестве аргумента и возвращает закодированную строку URI.Помните, что в encodeURIComponent() нельзя передавать весь URL-адрес (включая схему, например https: //). Это может фактически превратить его в неработающий URL. Например:
// for a whole URI don't use encodeURIComponent it will transform
// the / characters and the URL won't fucntion properly
console.info(encodeURIComponent("http://www.random.com/specials&char.html"));
// instead use encodeURI for whole URL's
console.info(encodeURI("http://www.random.com/specials&char.html"));Мы можем заметить, что если мы помещаем весь URL-адрес в encodeURIComponent, то передние косые черты (/) также преобразуются в специальные символы. Это приведет к тому, что URL-адрес больше не будет работать должным образом.
Поэтому (как следует из названия) используйте:
encodeURIComponent в определенной части URL-адреса, которую вы хотите закодировать.encodeURI по всему URL-адресу, который вы хотите закодировать.Вот ЖИВАЯ ДЕМО встроенных функций 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>
Используйте функцию fixedEncodeURIComponent, чтобы строго соблюдать RFC 3986:
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
По моему скромному мнению, самый элегантный способ кодирования параметров запроса - это создать объект с такими параметрами, как
const queryParams = { param1: 'value1', param2: 'value2' }
а затем закодируйте его, используя:
const queryString = new URLSearchParams(queryParams).toString()
как упоминалось в этом ответе: https://stackoverflow.com/a/53171438/7284582
Вы не должны использовать encodeURIComponent() напрямую.
Взгляните на RFC3986: Uniform Resource Identifier (URI): Generic Syntax
sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / " = "
The purpose of reserved characters is to provide a set of delimiting characters that are distinguishable from other data within a URI.
Эти зарезервированные символы из определения URI в RFC3986 НЕ экранируются encodeURIComponent().
Веб-документы MDN: encodeURIComponent ()
To be more stringent in adhering to RFC 3986 (which reserves !, ', (, ), and *), even though these characters have no formalized URI delimiting uses, the following can be safely used:
Используйте функцию MDN Web Docs ...
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
Сегодня (2020.06.12) я провожу тест скорости выбранных решений на MacOs HighSierra 10.13.6 в браузерах Chrome 83.0, Safari 13.1, Firefox 77.0. Эти результаты могут быть полезны для массового кодирования URL-адресов.
encodeURI (B) кажется самым быстрым, но это не рекомендуется для url-овescape (A) - быстрое кросс-браузерное решениеДля решений АBCDEF Я провожу два теста
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.info(`${f.name} ?url=${f(myUrl).replace(/^url=/,'')}`));This snippet only presents code of choosen solutionsПримеры результатов для Chrome
var myOtherUrl =
"http://example.com/index.html?url = " + encodeURIComponent(myUrl).replace(/%20/g,'+');
Не забудьте флаг / g, чтобы заменить все закодированные ''
Я всегда использую это для кодирования материалов для URL-адресов. Это совершенно безопасно, потому что он закодирует каждый символ, даже если его не нужно кодировать.
function urlEncode(text) {
encoded = '';
for (let char of text) {
encoded += '%' + char.charCodeAt(0).toString(16);
}
return encoded;
}
Попробуйте заглянуть в encodeURI () и decodeURI ().