Zakodować adres URL w JavaScript?

2469

Jak bezpiecznie kodować adres URL za pomocą JavaScript, aby można go było umieścić w ciągu GET?

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

Zakładam, że musisz zakodować myUrlzmienną w tym drugim wierszu?

pseudonim
źródło
22
Spróbuj spojrzeć na encodeURI () i decodeURI () .
Zack The Human
1
Możesz użyć tego narzędzia tutaj: phillihp.com/toolz/url-encode-decode
phillihp
2
encodeURIComponent ()
Andrew

Odpowiedzi:

2791

Sprawdź wbudowaną funkcję encodeURIComponent (str) i encodeURI (str) .
W twoim przypadku powinno to działać:

var myOtherUrl = 
       "http://example.com/index.html?url=" + encodeURIComponent(myUrl);
Buu Nguyen
źródło
12
Co powiesz na dodanie wyjaśnienia podanego przez @cms? escapejest również prawidłową opcją.
hitautodestruct
11
według @CMS encodeURInie jest tak naprawdę bezpieczne dla kodowania URL.
Ifnot
13
@AnaelFavre ponieważ jest przeznaczona do kodowania cały adres URL, który nie pozwala na znaki takie jak :, /, @itd. Te 2 metody nie mogą być używane zamiennie, trzeba wiedzieć, co kodowania użyć odpowiedniej metody.
Buu Nguyen,
Jak wspomniano w innej odpowiedzi na tej stronie , ta strona ładnie szczegółowo opisuje powód zastosowania tej metody
Brad Parks
1520

Masz trzy opcje:

  • escape() nie koduje: @*/+

  • encodeURI() nie koduje: ~!@#$&*()=:/,;?+'

  • encodeURIComponent() nie koduje: ~!*()'

Ale w twoim przypadku, jeśli chcesz przekazać adres URL do GETparametru innej strony, powinieneś użyć escapelub encodeURIComponent, ale nie encodeURI.

Zobacz pytanie Przepełnienie stosu Najlepsza praktyka: ucieczka lub encodeURI / encodeURIComponent w celu dalszej dyskusji.

CMS
źródło
76
Kodowanie znaków używane z klawiszem Escape jest zmienne. Trzymaj się z encodeURI i encodeURIComponent, które używają UTF-8.
erickson,
6
Bądź ostrożny. Ta ucieczka przekształca znaki spoza ASCII w sekwencje specjalne Unicode, takie jak %uxxx.
opteronn
4
Używam encodeURIComponent i zauważenie, że nie będzie kodować znaków potoku |
kevzettler 30.01.11
15
@kevzettler - dlaczego miałby to robić? Rury nie mają znaczenia semantycznego w URI.
nickf 31.01.11
4
@ GiovanniP: Ludzie, którzy zezwalają na wprowadzanie znaków niemieckich, francuskich, japońskich, chińskich, arabskich i przekazują te parametry przez GET lub POST.
Tseng
180

Trzymaj się encodeURIComponent(). Funkcja encodeURI()nie zawraca sobie głowy kodowaniem wielu znaków o znaczeniu semantycznym w adresach URL (np. „#”, „?” I „&”). escape()jest przestarzałe i nie zawraca sobie głowy kodowaniem znaków „+”, które będą interpretowane jako zakodowane spacje na serwerze (i, jak wskazali tutaj inni, nie kodują poprawnie znaków spoza ASCII kodujących adresy URL).

Jest ładne wyjaśnienie różnicy między encodeURI()iencodeURIComponent() gdzie indziej. Jeśli chcesz zakodować coś, aby można go było bezpiecznie dołączyć jako składnik identyfikatora URI (np. Jako parametr ciągu zapytania), chcesz go użyć encodeURIComponent().

Mike Brennan
źródło
83

Najlepszą odpowiedzią jest użycie encodeURIComponentna wartości w ciągu kwerendy (i nigdzie indziej).

Uważam jednak, że wiele interfejsów API chce zastąpić „” „” „”, więc musiałem użyć następujących opcji:

const value = encodeURIComponent(value).replace('%20','+');
const url = 'http://example.com?lang=en&key=' + value

escapejest różnie zaimplementowany w różnych przeglądarkach i encodeURInie koduje wielu znaków (takich jak #, a nawet /) - jest przeznaczony do użycia na pełnym identyfikatorze URI / URL bez jego uszkodzenia - co nie jest zbyt pomocne ani bezpieczne.

I jak wskazuje @Jochem poniżej, możesz chcieć używać encodeURIComponent()nazwy (każdego) folderu, ale z jakiegokolwiek powodu te interfejsy API wydają się nie chcieć +w nazwach folderów, więc zwykły stary encodeURIComponentdziała świetnie.

Przykład:

const escapedValue = encodeURIComponent(value).replace('%20','+');
const escapedFolder = encodeURIComponent('My Folder'); // no replace
const url = `http://example.com/${escapedFolder}/?myKey=${escapedValue}`;
Ryan Taylor
źródło
22
Uwaga:% 20 należy zastępować symbolami + po pierwszym znaku zapytania (który jest częścią adresu URL dotyczącą zapytania). Powiedzmy, że chcę przeglądać http://somedomain/this dir has spaces/info.php?a=this has also spaces. Powinien zostać przekonwertowany na: http://somedomain/this%20dir%20has%spaces/info.php?a=this%20has%20also%20spacesale wiele implementacji pozwala na zastąpienie „% 20” w zapytaniu przez „+”. Niemniej jednak nie można zamienić „% 20” na „+” w sekcji ścieżki adresu URL, spowoduje to błąd Nie znaleziono, chyba że masz katalog z +spacją.
Jochem Kuijpers,
@Jochem Kuijpers, na pewno nie umieściłbyś „+” w katalogu. Zastosowałbym to tylko do samych wartości parametrów zapytania (lub kluczy, jeśli to konieczne), a nie do całego adresu URL, a nawet całego ciągu zapytania.
Ryan Taylor
Chciałbym zastąpić wartość zamiast wyniku kodowania
njzk2
1
@ njzk2 niestety encodeURIComponent('+')dałby wam %2B, więc musielibyście użyć dwóch wyrażeń regularnych ... co, jak sądzę, jest trochę powodem, dlaczego to działa, ponieważ „+” są ”są ostatecznie zakodowane inaczej.
Ryan Taylor
Nie ma powodu tłumaczyć% 20 na „+”. Poprawną sekwencją zmiany znaczenia dla przestrzeni ASCII jest% 20, a nie „+”, która nie jest wymieniona w RFC 3986 ( tools.ietf.org/html/rfc3986 ). „+” został użyty w latach 90 .; jest teraz przestarzały i jest obsługiwany tylko ze względów starszych. Nie używaj tego.
xhienne
40

Jeśli używasz jQuery, wybrałbym $.parammetodę. Adres URL koduje pola mapowania obiektów na wartości, co jest łatwiejsze do odczytania niż wywołanie metody zmiany znaczenia dla każdej wartości.

$.param({a:"1=2", b:"Test 1"}) // gets a=1%3D2&b=Test+1
Maksym Kozlenko
źródło
Myślę, że podany przykład jest wystarczający. Jeśli potrzebujesz więcej informacji o $ .param na api.jquery.com/jquery.param
Maksym Kozlenko,
Prawie wszyscy używają jQuery i czuję się bardziej komfortowo z tym zamiast encoreURIComponent
Cyril Duchon-Doris
12

encodeURIComponent () jest właściwą drogą.

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

ALE należy pamiętać, że istnieją niewielkie różnice w stosunku do wersji php urlencode()i jak wspomniano w @CMS, nie koduje każdego znaku. Faceci na http://phpjs.org/functions/urlencode/ uczynili js równoważnym z 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', '+');
}
Adam Fischer
źródło
10

Aby zakodować adres URL, jak powiedziano wcześniej, masz dwie funkcje:

encodeURI()

i

encodeURIComponent()

Powodem tego jest to, że pierwszy zachowuje adres URL z ryzykiem pozostawienia zbyt wielu rzeczy bez zmian, a drugi koduje wszystko, co potrzebne.

Za pomocą pierwszego możesz skopiować nowo ocalony adres URL do paska adresu (na przykład) i działałoby. Jakkolwiek twoje nieskalowane '&' 'zakłócałyby ograniczniki pól,' = 'zakłócałyby nazwy i wartości pól, a' + 'wyglądałyby jak spacje. Ale w przypadku prostych danych, gdy chcesz zachować charakter URL tego, co uciekasz, działa to.

Drugi to wszystko, co musisz zrobić, aby upewnić się, że nic w ciągu nie koliduje z adresem URL. Pozostawia różne nieistotne znaki bez zmian, dzięki czemu adres URL pozostaje jak najbardziej czytelny dla człowieka bez ingerencji. Zakodowany w ten sposób adres URL nie będzie już działał jako adres URL bez jego usunięcia.

Jeśli więc możesz poświęcić trochę czasu, zawsze chcesz użyć encodeURIComponent () - przed dodaniem par nazwa / wartość zakoduj zarówno nazwę, jak i wartość za pomocą tej funkcji przed dodaniem jej do ciągu zapytania.

Trudno mi wymyślić powody, by użyć encodeURI () - pozostawię to mądrzejszym ludziom.

Gerard ONeill
źródło
5

Podobne rzeczy próbowałem z normalnym javascript

function fixedEncodeURIComponent(str){
     return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
}
Narayan Yerrabachu
źródło
5

Elegancki sposób

Moim skromnym zdaniem najbardziej eleganckim sposobem kodowania parametrów zapytań jest utworzenie obiektu o takich parametrach

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

a następnie koduj za pomocą:

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

jak wspomniano w tej odpowiedzi: https://stackoverflow.com/a/53171438/7284582

Qback
źródło
4

Aby uniknąć podwójnego kodowania, dobrym pomysłem jest odkodowanie adresu URL przed kodowaniem (jeśli masz do czynienia np. Z wpisanymi przez użytkownika adresami URL, które mogą być już zakodowane).

Powiedzmy, że mamy abc%20xyz 123dane wejściowe (jedna spacja jest już zakodowana):

encodeURI("abc%20xyz 123")            //   wrong: "abc%2520xyz%20123"
encodeURI(decodeURI("abc%20xyz 123")) // correct: "abc%20xyz%20123"
serg
źródło
4

Co to jest kodowanie adresów URL:

Adres URL należy zakodować, jeśli wewnątrz adresu URL znajdują się znaki specjalne. Na przykład:

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

W tym przykładzie możemy zauważyć, że wszystkie znaki oprócz łańcucha notEncodedsą kodowane znakami%. Kodowanie URL jest również znane jako kodowanie procentowe, ponieważ unika wszystkich znaków specjalnych za pomocą%. Następnie po tym znaku% każdy znak specjalny ma unikalny kod

Dlaczego potrzebujemy kodowania adresów URL:

Niektóre znaki mają specjalną wartość w ciągu adresu URL. Na przykład? znak oznacza początek ciągu zapytania. Aby z powodzeniem zlokalizować zasób w sieci, konieczne jest rozróżnienie, kiedy znak ma być ciągiem znaków lub częścią struktury adresu URL.

Jak możemy osiągnąć kodowanie URL w JS:

JS oferuje kilka wbudowanych funkcji narzędziowych, których możemy użyć do łatwego kodowania adresów URL. Są to dwie wygodne opcje:

  1. encodeURIComponent(): Bierze składnik URI jako argument i zwraca zakodowany ciąg URI.
  2. encodeURI(): Bierze URI jako argument i zwraca zakodowany ciąg URI.

Przykład i zastrzeżenia:

Pamiętaj, aby nie przekazywać całego adresu URL (w tym schematu, np. Https: //) do encodeURIComponent(). To może faktycznie przekształcić go w niedziałający adres URL. Na przykład:

// 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"));

Widzimy, że umieszczamy cały adres URL w encodeURIComponenttaki sposób, że ukośniki (/) są również konwertowane na znaki specjalne. Spowoduje to, że adres URL przestanie działać poprawnie.

Dlatego (jak sama nazwa wskazuje) użyj:

  1. encodeURIComponent na pewną część adresu URL, który chcesz zakodować.
  2. encodeURI na cały adres URL, który chcesz zakodować.
Willem van der Veen
źródło
3

Nic mi nie działało. Wszystko, co widziałem, to HTML strony logowania, która wraca na stronę klienta z kodem 200. (na początku 302, ale ta sama prośba Ajax ładuje stronę logowania w innym żądaniu Ajax, która miała być przekierowaniem, a nie ładowaniem zwykłego tekst strony logowania).

W kontrolerze logowania dodałem tę linię:

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

I w globalnym module obsługi Ajax zrobiłem to:

$(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;
            }
        }
    });
});

Teraz nie mam żadnego problemu i działa jak urok.

Asif Ashraf
źródło
2

Zakoduj ciąg adresu URL

    var url = $ ( lokalizacja ). attr ( „href” ); // uzyskać aktualne url // lub var url = 'Folder / index.html param = # 23dd & noobem = tak?' ; // lub podaj jeden 
    
      

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
Sangeet Shah
źródło
2

Oto LIVE DEMO od encodeURIComponent()i decodeURIComponent()JS wbudowanych funkcji:

<!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>
jonathana
źródło
1

Możesz użyć biblioteki esapi i zakodować swój adres URL za pomocą poniższej funkcji. Funkcja zapewnia, że ​​„/” nie zostaną utracone podczas kodowania, podczas gdy pozostała zawartość tekstu jest kodowana:

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

Mohith Maratt
źródło
1

Użyj fixedEncodeURIComponentfunkcji, aby ściśle przestrzegać RFC 3986 :

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}
Artur
źródło
1

Nie należy używać encodeURIComponent()bezpośrednio.

Spójrz na RFC3986: Uniform Resource Identifier (URI): Generic Składnia

sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

Celem znaków zastrzeżonych jest zapewnienie zestawu znaków ograniczających, które można odróżnić od innych danych w URI.

Te zastrzeżone znaki z definicji URI w RFC3986 NIE SĄ znakami ucieczki encodeURIComponent().

Dokumenty sieciowe MDN: encodeURIComponent ()

Aby być bardziej rygorystycznym w przestrzeganiu RFC 3986 (który zastrzega!, ', (,) I *), nawet jeśli te znaki nie mają sformalizowanych zastosowań ograniczania identyfikatorów URI, można bezpiecznie użyć następujących elementów:

Użyj funkcji MDN Web Docs ...

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}
HoldOffHunger
źródło