Khi nào bạn nên sử dụng lối thoát thay vì encodeURI / encodeURIComponent?


1392

Khi mã hóa một chuỗi truy vấn được gửi đến máy chủ web - khi nào bạn sử dụng escape()và khi nào bạn sử dụng encodeURI()hoặc encodeURIComponent():

Sử dụng lối thoát:

escape("% +&=");

HOẶC LÀ

sử dụng encodeURI () / encodeURIComponent ()

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

encodeURIComponent("var1=value1&var2=value2");

111
Đó là giá trị chỉ ra rằng encodeURIComponent("var1=value1&var2=value2")không trường hợp sử dụng điển hình. Ví dụ đó sẽ mã hóa =&, có lẽ không phải là những gì đã được dự định! encodeURIComponentthường được áp dụng riêng cho chỉ giá trị trong mỗi cặp giá trị khóa (phần sau mỗi cặp =).
Timothy Shields

3
bạn có cần làm gì để chìa khóa không? Điều gì nếu nó có một = trong nó? (điều đó thậm chí có thể chứ?)
Mala

3
@Mala Nói chung tôi vẫn chưa quen với lập trình web, nhưng những gì tôi đã sử dụng trong trải nghiệm hạn chế của mình là mã hóa khóa và giá trị riêng biệt, đảm bảo '=' ở lại: var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);- Có thể người khác biết cách tốt hơn.
nedshares

1
@nedshares Tôi đã chơi với nó, nhưng theo như tôi có thể nói rằng khóa dường như không được mã hóa ... ít nhất là không theo cùng một cách. Có lẽ nó chống lại thông số kỹ thuật để có một = trong khóa?
Mala

1
Cũng đáng chỉ ra rằng các triển khai JavaScript gần đây cung cấp URLURLSearchParams giao diện cấp cao hơn để thao tác URL và chuỗi truy vấn của chúng.
Bart Robinson

Câu trả lời:


1914

bỏ trốn()

Đừng dùng nó! escape()được định nghĩa trong phần B.2.1.2văn bản giới thiệu của Phụ lục B nói:

... Tất cả các tính năng và hành vi ngôn ngữ được chỉ định trong phụ lục này có một hoặc nhiều đặc điểm không mong muốn và trong trường hợp không sử dụng di sản sẽ bị xóa khỏi thông số kỹ thuật này. ...
... Các lập trình viên không nên sử dụng hoặc giả sử sự tồn tại của các tính năng và hành vi này khi viết mã ECMAScript mới ....

Hành vi:

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

Các ký tự đặc biệt được mã hóa ngoại trừ: @ * _ + -. /

Dạng thập lục phân cho các ký tự, có giá trị đơn vị mã là 0xFF trở xuống, là một chuỗi thoát hai chữ số : %xx.

Đối với các ký tự có đơn vị mã lớn hơn, định dạng bốn chữ số %uxxxxđược sử dụng. Điều này không được phép trong chuỗi truy vấn (như được định nghĩa trong RFC3986 ):

query       = *( pchar / "/" / "?" )
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded   = "%" HEXDIG HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
              / "*" / "+" / "," / ";" / "="

Dấu phần trăm chỉ được phép nếu nó được theo dõi trực tiếp bởi hai chữ số, phần trăm theo sau ulà không được phép.

mã hóa ()

Sử dụng encodeURI khi bạn muốn một URL hoạt động. Thực hiện cuộc gọi này:

encodeURI("http://www.example.org/a file with spaces.html")

để có được:

http://www.example.org/a%20file%20with%20spaces.html

Đừng gọi encodeURIComponent vì nó sẽ phá hủy URL và trả về

http%3A%2F%2Fwww.example.org%2Fa%20file%20with%20spaces.html

encodeURIComponent ()

Sử dụng encodeURIComponent khi bạn muốn mã hóa giá trị của tham số URL.

var p1 = encodeURIComponent("http://example.org/?a=12&b=55")

Sau đó, bạn có thể tạo URL bạn cần:

var url = "http://example.net/?param1=" + p1 + "&param2=99";

Và bạn sẽ nhận được URL hoàn chỉnh này:

http://example.net/?param1=http%3A%2F%2Fexample.org%2F%Ffa%3D12%26b%3D55&param2=99

Lưu ý rằng encodeURIComponent không thoát khỏi 'ký tự. Một lỗi phổ biến là sử dụng nó để tạo các thuộc tính html như href='MyUrl', có thể bị lỗi tiêm. Nếu bạn đang xây dựng html từ các chuỗi, hãy sử dụng "thay 'cho dấu ngoặc kép thuộc tính hoặc thêm một lớp mã hóa bổ sung ( 'có thể được mã hóa thành% 27).

Để biết thêm thông tin về loại mã hóa này, bạn có thể kiểm tra: http://en.wikipedia.org/wiki/Percent-encoding


31
@Francois, tùy thuộc vào máy chủ nhận, nó có thể không giải mã chính xác cách thoát mã hóa các ký tự ASCII hoặc không phải ASCII trên, chẳng hạn như: "Ví dụ", lớp FieldStorage của Python sẽ không giải mã đúng chuỗi trên.
Ray

22
@Francois esc () mã hóa các ký tự 128 ASCII thấp hơn ngoại trừ các chữ cái, chữ số và *@-_+./ trong khi unescape () là nghịch đảo của esc (). Theo như tôi có thể nói, chúng là các chức năng kế thừa được thiết kế để mã hóa URL và chỉ được triển khai để tương thích ngược. Nói chung, chúng không nên được sử dụng trừ khi tương tác với một ứng dụng / dịch vụ web / vv được thiết kế cho chúng.
Anthony DiSanti

3
Tất nhiên trừ khi bạn đang cố gắng truyền URL dưới dạng thành phần URI trong trường hợp đó gọi là encodeURIComponent.
tom

4
Tại sao nó không xử lý trích dẫn duy nhất?
Eric

11
@Eric Nó không mã hóa trích dẫn đơn, bởi vì trích dẫn đơn là một ký tự hoàn toàn hợp lệ xảy ra trong URI ( RFC-3986 ). Sự cố xảy ra khi bạn nhúng URI trong HTML, trong đó trích dẫn đơn không phải là ký tự hợp lệ. Sau đó, các URI cũng phải được "mã hóa HTML" (sẽ thay thế 'bằng ') trước khi được đặt vào tài liệu HTML.
Lee

441

Sự khác biệt giữa encodeURI()encodeURIComponent()chính xác là 11 ký tự được mã hóa bởi encodeURIComponent nhưng không phải bởi encodeURI:

Bảng với mười điểm khác biệt giữa encodeURI và encodeURIComponent

Tôi đã tạo bảng này dễ dàng với console.table trong Google Chrome với mã này:

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


Đây không phải là trình duyệt phụ thuộc?
Pacerier

4
@bladnman encodeURI và encodeURIComponent sẽ hoạt động theo cách này trong tất cả các trình duyệt chính. Bạn có thể kiểm tra mã trên trong Chrome và Firefox vì cả hai đều hỗ trợ console.table. Trong các trình duyệt khác (bao gồm Firefox và Chrome), bạn có thể sử dụng mã sau: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
Ý tôi là @Pacerier :)
Johann Echavarria

@Pacerier nên giống hệt nhau trong các trình duyệt khác nhau trừ khi spec ban đầu là quá mơ hồ ... cũng thấy stackoverflow.com/questions/4407599/...
Christophe Roussy

2
TÔI CẦN TĂNG CƯỜNG THỜI GIAN NÀY! Thật không may, chỉ có thể upvote một lần.
Ramazan Polat

46

Tôi tìm thấy bài viết này khai sáng: Javascript Madness: Phân tích chuỗi truy vấn

Tôi đã tìm thấy nó khi tôi đang cố gắng nhấn mạnh tại sao giải mã không phải là giải mã chính xác '+'. Đây là một đoạn trích:

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
Bài viết bạn liên kết để chứa rất nhiều điều vô nghĩa. Dường như với tôi, bản thân tác giả không hiểu chức năng nào được sử dụng đúng cách cho ...
Christoph

2
@Christoph Tất cả có vẻ hợp lý với tôi. Đặc biệt, tôi đồng ý với anh ta rằng encodeURIdường như nó chỉ hữu ích trong trường hợp cạnh khá tối nghĩa và thực sự không cần phải tồn tại. Tôi có một số khác biệt về quan điểm với anh ta, nhưng tôi không thấy bất cứ điều gì hoàn toàn sai hoặc ngu ngốc trong đó. Chính xác thì bạn nghĩ gì là vô nghĩa?
Đánh dấu Amery

1
Các enctypethuộc tính của FORMquy định cụ thể các phần tử kiểu nội dung sử dụng để mã hóa các thiết lập hình thức dữ liệu để trình máy chủ. application / x-www-form-urlencoding Đây là loại nội dung mặc định. Các biểu mẫu được gửi với loại nội dung này phải được mã hóa như sau: [...] Các ký tự khoảng trắng được thay thế bằng `` + 'và [...] Các ký tự không chữ và số được thay thế bằng`% HH', [...] Tham chiếu: HTML4 Sepc
cychoi

2
encodeURIComponent ('A + B'). thay thế (/ \% 20 / g, '+') + '\ n' + decodeURIComponent ("A +% 2B + B" .replace (/ \ + / g, '% 20' ));
Zlatin Zlatev

39

encodeURIComponent không mã hóa -_.!~*'(), gây ra vấn đề trong việc đăng dữ liệu lên php trong chuỗi xml.

Ví dụ:
<xml><text x="100" y="150" value="It's a value with single quote" /> </xml>

Lối thoát chung với 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

Bạn có thể thấy, trích dẫn duy nhất không được mã hóa. Để giải quyết vấn đề, tôi đã tạo hai hàm để giải quyết vấn đề trong dự án của mình, cho Mã hóa 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");
}

Để giải mã 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
Nó cũng không làm dấu # (pound / hash / number), là% 23.
xr280xr

1
@ xr280xr Ý bạn là gì? encodeURIComponent không mã hóa # đến% 23 (có thể nó không có trong năm 2014?)
David Balažic

38

encodeURI () - hàm esc () dành cho thoát javascript, không phải HTTP.


Nếu tôi có một url như thế này: var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"... Và tôi muốn truy cập nó thông qua API Google Ajax, như thế này: var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;... thì tôi phải sử dụng escape(url). encodeURI(url)Dường như không hoạt động với các tham số như thế.
Lance Pollard

15
bạn nên sử dụng ecnodeURIComponent (url)
Ustaman Sangat

2
Tất cả 3 chức năng có vấn đề của họ. Tốt hơn là tạo chức năng của riêng bạn mà thực hiện công việc.
Jerry Joseph

17

Bảng so sánh nhỏ Java so với JavaScript so với 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

Tôi khuyên bạn không nên sử dụng một trong những phương pháp đó. Viết chức năng của riêng bạn mà làm điều đúng.

MDN đã đưa ra một ví dụ tốt về mã hóa url được hiển thị bên dưới.

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
thật là một câu trả lời tuyệt vời (nếu nó tương thích qua chrome và firefox trong khi không mắc lỗi nào)
yan bellavance

10

Cũng nên nhớ rằng tất cả chúng đều mã hóa các bộ ký tự khác nhau và chọn bộ ký tự bạn cần một cách thích hợp. encodeURI () mã hóa ít ký tự hơn encodeURIComponent (), mã hóa ít hơn (và cũng khác nhau, theo điểm của dannyp) so với esc ().


8

Với mục đích mã hóa javascript đã đưa ra ba hàm sẵn có -

  1. escape()- không mã hóa @*/+ Phương thức này không được dùng sau ECMA 3 vì vậy cần tránh.

  2. encodeURI()- không mã hóa ~!@#$&*()=:/,;?+' Giả định rằng URI là một URI hoàn chỉnh, do đó không mã hóa các ký tự dành riêng có ý nghĩa đặc biệt trong URI. Phương pháp này được sử dụng khi mục đích là chuyển đổi URL hoàn chỉnh thay vì một số phân đoạn URL đặc biệt. Ví dụ - encodeURI('http://stackoverflow.com'); sẽ đưa ra - http://stackoverflow.com

  3. encodeURIComponent()- không mã hóa - _ . ! ~ * ' ( ) Hàm này mã hóa thành phần Định danh tài nguyên đồng nhất (URI) bằng cách thay thế từng phiên bản của một số ký tự nhất định bằng một, hai, ba hoặc bốn chuỗi thoát biểu thị mã hóa UTF-8 của ký tự. Phương pháp này nên được sử dụng để chuyển đổi một thành phần của URL. Chẳng hạn, một số đầu vào của người dùng cần được thêm vào Ví dụ - encodeURIComponent('http://stackoverflow.com'); sẽ cung cấp - http% 3A% 2F% 2Fstackoverflow.com

Tất cả mã hóa này được thực hiện trong UTF 8 tức là các ký tự sẽ được chuyển đổi ở định dạng UTF-8.

encodeURIComponent khác với encodeURI ở chỗ nó mã hóa các ký tự dành riêng và ký hiệu số # của encodeURI


3

Tôi đã thấy rằng thử nghiệm các phương pháp khác nhau là kiểm tra sự tỉnh táo ngay cả khi đã xử lý tốt những công dụng và khả năng khác nhau của chúng.

Cuối cùng, tôi thấy trang web này cực kỳ hữu ích để xác nhận sự nghi ngờ của tôi rằng tôi đang làm một cái gì đó phù hợp. Nó cũng đã được chứng minh là hữu ích cho việc giải mã một chuỗi mã hóa, có thể khá khó khăn để diễn giải. Một dấu trang tuyệt vời để có:

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


2

Câu trả lời được chấp nhận là tốt. Để mở rộng về phần cuối cùng:

Lưu ý rằng encodeURIComponent không thoát khỏi ký tự '. Một lỗi phổ biến là sử dụng nó để tạo các thuộc tính html như href = 'MyUrl', có thể bị lỗi tiêm. Nếu bạn đang xây dựng html từ các chuỗi, hãy sử dụng "thay vì 'cho dấu ngoặc kép thuộc tính hoặc thêm một lớp mã hóa bổ sung (' có thể được mã hóa thành% 27).

Nếu bạn muốn ở bên an toàn, phần trăm mã hóa các ký tự không được giám sát cũng nên được mã hóa.

Bạn có thể sử dụng phương pháp này để thoát chúng (nguồn Mozilla )

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

// fixedEncodeURIComponent("'") --> "%27"

2

Viết lại hiện đại câu trả lời của @ 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
        )
)

Hoặc nếu bạn có thể sử dụng bảng, hãy thay thế console.logbằng console.table(đối với đầu ra đẹp hơn).


2

Lấy cảm hứng từ bàn của Johann , tôi đã quyết định mở rộng bảng. Tôi muốn xem những ký tự ASCII nào được mã hóa.

ảnh chụp màn hình của console.table

Bảng chỉ hiển thị các ký tự được mã hóa. Các ô trống có nghĩa là các ký tự gốc và ký tự được mã hóa giống nhau.


Chỉ cần được bổ sung, tôi thêm bảng khác cho urlencode()vs rawurlencode(). Sự khác biệt duy nhất dường như là mã hóa ký tự không gian.

ảnh chụp màn hình của 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

Tôi có chức năng này ...

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 esc () không được dùng nữa nhưng không bao giờ tham khảo w3schools.com. xem w3fools.com
Jerry Joseph

4
@Christian Vielma - Một số tìm ra tài liệu tham khảo tại W3Schoolsít gây tranh cãi và hữu ích . Không phải ai cũng đồng ý rằng W3Schools không nên được tham khảo.
DavidRR

2
W3Schools có được một bản rap tệ. Chắc chắn rằng chúng không phải lúc nào cũng chính xác, nhưng một lần nữa tôi lại bắt gặp rất nhiều bài viết trên blog cũng hoàn toàn sai. Đối với tôi đôi khi nó là một điểm khởi đầu tuyệt vời chỉ để tìm hiểu một số thuật ngữ và sau đó tôi đi sâu hơn một chút với các tài nguyên khác. Quan trọng nhất là một nguồn tài nguyên duy nhất không bao giờ nên theo Kinh thánh khi nói đến loại công cụ này.
ryandlf

Có vẻ như @molokoloco đã viết chức năng này như một bản dự phòng cho các phiên bản encodeURIkhông tồn tại nhưng escapetồn tại.
SOFe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.