Cái gì hợp lệ và cái gì không trong truy vấn URI?


99

Bối cảnh (câu hỏi thêm xuống)

Tôi đã đọc đi đọc lại cái này trên Google để đọc các câu hỏi RFC và SO cố gắng giải mã này, nhưng tôi vẫn không có jack.

Vì vậy, tôi đoán chúng ta chỉ bỏ phiếu cho câu trả lời "tốt nhất" và đó là nó, hoặc?

Về cơ bản, nó tóm tắt về điều này.

3.4. Thành phần truy vấn

Thành phần truy vấn là một chuỗi thông tin được tài nguyên giải thích.

query = *uric

Trong thành phần truy vấn, các ký tự ";", "/", "?", ":", "@", "&", "=", "+", "," Và "$" được dành riêng.

Điều đầu tiên làm tôi bối rối là * uric được định nghĩa như thế này

uric = reserved | unreserved | escaped

reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

Tuy nhiên, điều này phần nào được làm rõ bởi các đoạn văn như

Lớp cú pháp "dành riêng" ở trên đề cập đến những ký tự được phép trong URI, nhưng có thể không được phép trong một thành phần cụ thể của cú pháp URI chung; chúng được sử dụng làm dấu phân cách của các thành phần được mô tả trong Phần 3.

Các ký tự trong tập hợp "dành riêng" không được bảo lưu trong mọi ngữ cảnh. Tập hợp các ký tự thực sự dành riêng trong bất kỳ thành phần URI nhất định nào được xác định bởi thành phần đó. Nói chung, một ký tự được dành riêng nếu ngữ nghĩa của URI thay đổi nếu ký tự được thay thế bằng mã hóa US-ASCII đã thoát của nó.

Đoạn trích cuối cùng này có cảm giác hơi ngược, nhưng nó nói rõ rằng dàn nhân vật được bảo lưu phụ thuộc vào ngữ cảnh. Tuy nhiên, 3.4 nói rằng tất cả các ký tự dành riêng đều được dành riêng trong một thành phần truy vấn, tuy nhiên, điều duy nhất có thể thay đổi ngữ nghĩa ở đây là thoát khỏi dấu hỏi (?) Vì URI không xác định khái niệm chuỗi truy vấn.

Tại thời điểm này, tôi đã từ bỏ hoàn toàn RFC nhưng thấy RFC 1738 đặc biệt thú vị.

URL HTTP có dạng:

http://<host>:<port>/<path>?<searchpart>

Trong các thành phần <path> và <searchpart>, "/", ";", "?" được đặt trước. Ký tự "/" có thể được sử dụng trong HTTP để chỉ định cấu trúc phân cấp.

Tôi giải thích điều này ít nhất là liên quan đến các URL HTTP mà RFC 1738 thay thế RFC 2396. Bởi vì truy vấn URI không có khái niệm về chuỗi truy vấn cũng như việc giải thích dành riêng không thực sự cho phép tôi xác định các chuỗi truy vấn như tôi đã quen hiện đang làm.

Câu hỏi

Tất cả điều này bắt đầu khi tôi muốn chuyển một danh sách các số cùng với yêu cầu của một tài nguyên khác. Tôi không nghĩ nhiều về nó và chỉ chuyển nó dưới dạng các giá trị được phân tách bằng dấu phẩy. Tôi ngạc nhiên mặc dù dấu phẩy đã được thoát ra. Truy vấn page.html?q=1,2,3được mã hóa biến thành page.html?q=1%2C2%2C3nó hoạt động, nhưng nó xấu xí và không mong đợi. Đó là khi tôi bắt đầu xem qua RFC.

Câu hỏi đầu tiên của tôi chỉ đơn giản là, mã hóa dấu phẩy có thực sự cần thiết không?

Câu trả lời của tôi, theo RFC 2396: có, theo RFC 1738: không

Sau đó, tôi tìm thấy các bài đăng liên quan về việc chuyển danh sách giữa các yêu cầu. Nơi mà cách tiếp cận csv được coi là tồi tệ. Điều này đã hiển thị thay thế, (chưa thấy điều này trước đây).

page.html?q=1;q=2;q=3

Câu hỏi thứ hai của tôi, đây có phải là một URL hợp lệ không?

Câu trả lời của tôi, theo RFC 2396: không, theo RFC 1738: không (; được bảo lưu)

Tôi không gặp bất kỳ vấn đề nào với việc chuyển csv miễn là đó là số, nhưng có, bạn có nguy cơ phải mã hóa và giải mã các giá trị qua lại nếu dấu phẩy đột nhiên cần cho việc khác. Dù sao tôi đã thử chuỗi truy vấn dấu chấm phẩy với ASP.NET và kết quả không như tôi mong đợi.

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

Tôi không thấy điều này khác biệt nhiều như thế nào so với cách tiếp cận csv vì khi tôi yêu cầu "a", tôi nhận được một chuỗi có dấu phẩy trong đó. ASP.NET chắc chắn không phải là một triển khai tham chiếu nhưng nó vẫn chưa làm tôi thất vọng.

Nhưng quan trọng nhất - câu hỏi thứ ba của tôi - đặc điểm kỹ thuật cho việc này là ở đâu? và bạn sẽ làm gì hoặc cho vấn đề đó không làm gì?


Làm thế nào RFC 1738 có thể thay thế RFC 2396, khi RFC 2396 được xuất bản gần 4 năm sau đó?
Matthew Flaschen

1
Liên quan đến URL và những gì thực tế có ý nghĩa, tôi hiểu rằng nó đúng. (Thay thế có lẽ không phải là từ phù hợp vì nó được sử dụng trong thuật ngữ RFC cho các RFC cũ không được dùng nữa, RFC 1738 không cảm thấy bị phản đối khi nó là thông số kỹ thuật duy nhất nếu được tìm thấy cho phép bạn đặt một chuỗi truy vấn trong phần tìm kiếm của URL)
John Leidegren

Câu trả lời:


68

Việc một ký tự được dành riêng trong một thành phần URL chung không có nghĩa là nó phải được thoát khi nó xuất hiện trong thành phần hoặc trong dữ liệu trong thành phần. Ký tự cũng phải được định nghĩa là dấu phân cách trong cú pháp chung hoặc theo lược đồ cụ thể và hình thức của ký tự phải nằm trong dữ liệu.

Tiêu chuẩn hiện tại cho các URI chung là RFC 3986 , có nghĩa là:

2.2. Nhân vật dành riêng

URI bao gồm các thành phần và thành phần con được phân cách bằng các ký tự trong tập hợp "dành riêng". Các ký tự này được gọi là "dành riêng" vì chúng có thể (hoặc không) được định nghĩa là dấu phân cách theo cú pháp chung, theo cú pháp của từng lược đồ cụ thể hoặc theo cú pháp triển khai cụ thể của thuật toán hội nghị của URI. Nếu dữ liệu cho một thành phần URI sẽ xung đột với mục đích của một ký tự dành riêng là dấu phân cách [đã thêm phần nhấn mạnh], thì dữ liệu xung đột phải được mã hóa theo phần trăm trước khi URI được hình thành.

   dành riêng = gen-delims / sub-delims

   gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"

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

3.3. Thành phần đường dẫn

[...]
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
[...]

3.4 Thành phần truy vấn

[...]
      truy vấn = * (pchar / "/" / "?")

Do đó, dấu phẩy được cho phép rõ ràng trong các chuỗi truy vấn và chỉ cần được thoát trong dữ liệu nếu các lược đồ cụ thể xác định nó như một dấu phân cách. Lược đồ HTTP không sử dụng dấu phẩy hoặc dấu chấm phẩy làm dấu phân cách trong các chuỗi truy vấn, vì vậy chúng không cần phải được thoát. Các trình duyệt có tuân theo tiêu chuẩn này hay không là một vấn đề khác.

Sử dụng CSV sẽ hoạt động tốt đối với dữ liệu chuỗi, bạn chỉ cần tuân theo các quy ước CSV tiêu chuẩn và trích dẫn dữ liệu hoặc thoát khỏi dấu phẩy với dấu gạch chéo ngược.

Đối với RFC 2396, nó cũng cho phép các dấu phẩy không thoát trong chuỗi truy vấn HTTP:

2.2. Nhân vật dành riêng

Nhiều URI bao gồm các thành phần bao gồm hoặc được phân tách bằng các ký tự đặc biệt nhất định. Các ký tự này được gọi là "dành riêng", vì việc sử dụng chúng trong thành phần URI được giới hạn cho mục đích dành riêng của chúng. Nếu dữ liệu cho một thành phần URI sẽ xung đột với mục đích dành riêng, thì dữ liệu xung đột phải được thoát trước khi hình thành URI.

Vì dấu phẩy không có mục đích dành riêng trong lược đồ HTTP, chúng không cần phải được thoát trong dữ liệu. Lưu ý từ § 2.3 về các ký tự dành riêng là những ký tự thay đổi ngữ nghĩa khi mã hóa phần trăm chỉ áp dụng chung; các ký tự có thể được mã hóa theo phần trăm mà không thay đổi ngữ nghĩa cho các lược đồ cụ thể và vẫn được bảo lưu.


23

Để trả lời những gì hợp lệ trong chuỗi truy vấn, tôi đã kiểm tra những ký tự đặc biệt nào được chrome thay thế khi đưa ra yêu cầu:

Space -> %20
! -> !
" -> %22
# -> removed, marks the end of the query string
% -> %
& -> &
' -> %27
( -> (
) -> )
* -> *
+ -> + (this usually means blank when received at the server, so encode if necessary)
, -> ,
- -> -
. -> .
/ -> /
: -> :
; -> ;
< -> %3C
= -> =
> -> %3E
? -> ?
@ -> @
[ -> [
\ -> \
] -> ]
^ -> ^
_ -> _
` -> `
{ -> {
| -> |
} -> }
~ -> ~

Extended ASCII (like °) -> Every character from this set is encoded

Lưu ý: Điều đó có lẽ không có nghĩa là bạn không nên thoát các ký tự không được thay thế khi bạn tạo URI cho các liên kết. Ví dụ: nó thường được khuyến nghị không sử dụng ~trong URI vì các vấn đề tương thích nhưng nó vẫn là một ký tự hợp lệ.

Một ví dụ khác là dấu cộng hợp lệ nhưng thường được coi là dấu trống được mã hóa khi máy chủ nhận nó như một phần của yêu cầu. Vì vậy, nó phải được mã hóa ngay cả khi hợp lệ khi mục đích của nó là đại diện cho dấu cộng chứ không phải dấu cách.

Vì vậy, để trả lời những gì nên được mã hóa: Các ký tự không hợp lệ và các ký tự mà bạn muốn xử lý theo nghĩa đen nhưng có ý nghĩa đặc biệt hoặc có thể gây ra sự cố ở cuối máy chủ.


/programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2một tham số truy vấn hợp lệ?
Sumit Jain

@SumitJain Không, bởi vì #không thể xuất hiện bên trong phần truy vấn của URI nguyên trạng. Bạn sẽ cần mã hóa nó thành %23URI như vậy /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232.
Đại

10

Chỉ dùng ?q=1+2+3

Tôi đang trả lời ở đây câu hỏi thứ tư :) không hỏi nhưng tất cả bắt đầu bằng: làm cách nào để chuyển danh sách các số được phân tách bằng dấu phẩy? Đối với tôi, có vẻ như cách tiếp cận tốt nhất chỉ là chuyển chúng được phân cách bằng dấu cách, nơi các dấu cách sẽ được mã hóa dạng url +. Hoạt động tốt, miễn là bạn biết các giá trị trong danh sách không chứa khoảng trắng (một số thứ có xu hướng không).


Mặc dù đây phải là một bình luận (vì nó không trả lời câu hỏi), cảm ơn bạn. +thậm chí còn có ý nghĩa hơn trong trường hợp cụ thể mà tôi đang tìm cách sử dụng dấu phẩy.
Gajus

6

trang.html? q = 1; q = 2; q = 3

đây có phải là một URL hợp lệ?

Đúng. Các ;được dành riêng, nhưng không phải bởi một RFC. Ngữ cảnh xác định thành phần này là định nghĩa của application/x-www-form-urlencodedloại phương tiện, là một phần của tiêu chuẩn HTML (mục 17.13.4.1 ). Cụ thể là ghi chú lén lút ẩn trong phần B.2.2 :

Chúng tôi khuyến nghị rằng những người triển khai máy chủ HTTP và cụ thể là những người triển khai CGI hỗ trợ việc sử dụng ";" thay cho "&" để tác giả đỡ gặp rắc rối khi thoát các ký tự "&" theo cách này.

Rất tiếc, nhiều khung kịch bản phía máy chủ phổ biến bao gồm ASP.NET không hỗ trợ cách sử dụng này.


Vì vậy, trong khi ?q=1;q=2;q=3truy vấn hợp lệ, nó là mơ hồ: một số khung công tác phía máy chủ sẽ đọc nó có nghĩa là { q: '1;q=2;q=3' }, một số khung công tác khác có thể làm điều đó tương tự { q: {'1', '2', '3'}}.
Nas Banov

1
Đúng. Và điều tồi tệ hơn, HTML5 hiện không bao gồm ngôn ngữ nói về ;, có nghĩa là HTML4 và HTML5 không nhất quán. Rất tiếc, sự nguy hiểm của ngôn ngữ không chuẩn mực trong một tài liệu kỹ thuật ...
bobince

@NasBanov Tuy nhiên những người khác (ví dụ như PHP) sẽ giải thích nó như{ q: 3 }
Nicholas Shanks

1
@NicholasShanks - nơi PHP tham gia, tất cả các cược đã tắt! :)
Nas Banov

1

Tôi muốn lưu ý rằng đó page.html?q=1&q=2&q=3cũng là một url hợp lệ. Đây là một cách hoàn toàn hợp pháp để thể hiện một mảng trong một chuỗi truy vấn. Công nghệ máy chủ của bạn sẽ xác định cách trình bày chính xác.

Trong ASP cổ điển, bạn kiểm tra Response.QueryString("q").Countvà sau đó sử dụng Response.QueryString("q")(0)(và (1) và (2)).

Lưu ý rằng bạn cũng thấy điều này trong ASP.NET của mình (tôi nghĩ nó không phải là dự định, nhưng hãy xem):

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

Lưu ý rằng dấu chấm phẩy bị bỏ qua, vì vậy bạn đã axác định hai lần và bạn nhận giá trị của nó hai lần, được phân tách bằng dấu phẩy. Sử dụng tất cả các ký hiệu và Default.aspx?a=1&a=2&b=1&a=3sẽ mang lại kết quả alà "1,2,3". Nhưng tôi chắc chắn rằng có một phương pháp để lấy từng phần tử riêng lẻ, trong trường hợp bản thân các phần tử chứa dấu phẩy. Nó chỉ đơn giản là thuộc tính mặc định của QueryString không được lập chỉ mục nối các giá trị con với nhau bằng dấu phân cách bằng dấu phẩy.


1

Tôi gặp vấn đề tương tự. URL được siêu liên kết là URL của bên thứ ba và đang mong đợi một danh sách các tham số page.html?q=1,2,3CHỈ ở định dạng và URL page.html?q=1%2C2%2C3không hoạt động. Tôi đã có thể làm cho nó hoạt động bằng cách sử dụng javascript. Có thể không phải là cách tiếp cận tốt nhất nhưng có thể kiểm tra giải pháp ở đây nếu nó giúp được bất kỳ ai.


-3

Nếu bạn đang gửi các ký tự ĐÃ KÍCH THÍCH tới tệp FLASH / SWF , thì bạn nên KÍCH THÍCH ký tự hai lần !! (vì trình phân tích cú pháp Flash)

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.