Що є дійсним, а що ні в запиті URI?


100

Передумови (питання далі)

Я гуглив це назад і вперед, читаючи RFC і ТАК, намагаючись зламати це, але в мене все ще немає джека.

Тож я гадаю, що ми просто голосуємо за "найкращу" відповідь, і це все, чи?

В основному це зводиться до цього.

3.4. Компонент запиту

Компонент запиту - це рядок інформації, яку слід інтерпретувати ресурсом.

query = *uric

У компоненті запиту символи ";", "/", "?", ":", "@", "&", "=", "+", "," Та "$" зарезервовані.

Перше, що мене змушує - це те, що * сечовизначення визначено так

uric = reserved | unreserved | escaped

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

Це, однак, дещо прояснено такими абзацами, як

Вище "зарезервований" клас синтаксису відноситься до тих символів, які дозволені в URI, але які можуть бути дозволені в межах певного компонента загального синтаксису URI; їх використовують як роздільники компонентів, описаних у розділі 3.

Символи в "зарезервованому" наборі не зарезервовані у всіх контекстах. Набір символів, фактично зарезервованих в межах будь-якого даного компонента URI, визначається цим компонентом. Як правило, символ зарезервований, якщо семантика URI змінюється, якщо символ замінюється на його кодированное US-ASCII кодування.

Цей останній уривок відчувається дещо назад, але чітко вказується, що зарезервований набір символів залежить від контексту. Проте 3.4 говорить, що всі зарезервовані символи зарезервовані в компоненті запиту, проте єдине, що змінило б тут семантику, - це уникнути знака питання (?), Оскільки URI не визначають поняття рядка запиту.

На цей момент я повністю відмовився від RFC, але вважав RFC 1738 особливо цікавою.

URL-адреса HTTP має форму:

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

У компонентах <path> та <searchpart> "/", ";", "?" зарезервовані. Символ "/" може використовуватися в HTTP для позначення ієрархічної структури.

Я інтерпретую це принаймні щодо HTTP-адрес, які RFC 1738 замінює RFC 2396. Оскільки запит URI не має поняття рядка запиту, також інтерпретація зарезервованого не дозволяє мені визначати рядки запиту, як я звик робити до цього часу.

Питання

Все почалося, коли я хотів передати список номерів разом із запитом іншого ресурсу. Я не надто думав про це, а просто передав це як значення, розділені комами. На моє здивування, хоч кома втекла. page.html?q=1,2,3Зашифрований запит, який перетворився на page.html?q=1%2C2%2C3це, працює, але це негарно і не очікував цього. Ось тоді я почав переглядати RFC.

Моє перше запитання просто, чи справді потрібно кодувати коми?

Моя відповідь, згідно RFC 2396: так, згідно з RFC 1738: ні

Пізніше я знайшов відповідні пости щодо передачі списків між запитами. Де підхід csv вважався поганим. Це з'явилося натомість, (я цього раніше не бачив).

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

Моє друге питання, чи це дійсна URL-адреса?

Моя відповідь, згідно RFC 2396: ні, згідно з RFC 1738: ні (; зарезервовано)

У мене немає проблем з передачею csv, якщо це цифри, але так, ви ризикуєте кодувати та декодувати значення вперед і назад, якщо раптом кома потрібна для чогось іншого. У будь-якому разі я спробував набір запитів на колонку з двокрапкою з ASP.NET, і результат був не таким, як я очікував.

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

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

Я не бачу, як це сильно відрізняється від підходу csv, оскільки коли я прошу "a", я отримую рядок із комами в ньому. ASP.NET, безумовно, не є еталонною реалізацією, але вона мене ще не підвела.

Але найголовніше - моє третє питання - де специфікація для цього? і що б ви зробили або з цього питання не зробили?


Як RFC 1738 може замінити RFC 2396, коли RFC 2396 був опублікований майже через 4 роки?
Метью Флашен

1
Що стосується URL-адрес і того, що практично має сенс, це моє тлумачення. (supersede, мабуть, не є правильним словом, оскільки він використовується в термінології RFC для застарілих старих RFC, RFC 1738 не відчуває все, що застаріло, коли це єдиний специфікатор, якщо знайдений, що дозволяє помістити рядок запиту в пошукову частину URL-адреси)
Джон Лейдегрен

Відповіді:


69

Те, що символ зарезервований у загальному компоненті URL-адреси, не означає, що його потрібно уникати, коли він з’являється всередині компонента або в даних у компоненті. Символ також повинен бути визначений як роздільник у загальному синтаксисі або специфічній для схеми, а зовнішній вигляд символу повинен бути в межах даних.

Поточним стандартом для загальних URI є RFC 3986 , який повинен говорити:

2.2. Зарезервовані персонажі

URI включають компоненти та підкомпоненти, які розділені символами в "зарезервованому" наборі. Ці символи називаються "зарезервованими", оскільки вони можуть (або не можуть) бути визначені як роздільники за загальним синтаксисом, кожним синтаксисом, специфічним для схеми, або синтаксисом, орієнтованим на реалізацію алгоритму перенаправлення URI. Якщо дані для компонента URI суперечать призначенню зарезервованого символу як роздільника [наголос додано], то конфліктуючі дані повинні бути закодовані у відсотках до формування URI.

   зарезервовано = gen-delims / sub-delims

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

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

3.3. Компонент шляху

[...]
pchar = без резервування / кодування pct / субделіми / ":" "" "
[...]

3.4 Компонент запиту

[...]
      запит = * (pchar / "/" / "?")

Таким чином, коми явно дозволені в рядках запиту, і їх потрібно уникати в даних, лише якщо конкретні схеми визначають їх як роздільник. Схема HTTP не використовує кому або крапку з комою як роздільник у рядках запитів, тому їх не потрібно екранувати. Чи браузери дотримуються цього стандарту - інша справа.

Використання CSV повинно спрацьовувати для рядкових даних, просто потрібно дотримуватися стандартних угод CSV та цитувати дані або уникати коси з зворотними нахилами.

Що стосується RFC 2396, він також дозволяє використовувати нерозмірні коми в рядках запитів HTTP:

2.2. Зарезервовані персонажі

Багато URI включають компоненти, що складаються або обмежені певними спеціальними символами. Ці символи називаються "зарезервованими", оскільки їх використання в компоненті URI обмежено їх зарезервованим призначенням. Якщо дані для компонента URI суперечать зарезервованій меті, то перед тим, як формувати URI, слід уникати суперечливих даних.

Оскільки коми не мають зарезервованої мети за схемою HTTP, їх не потрібно уникати в даних. Примітка з § 2.3 про зарезервовані символи - це ті, що змінюють семантику, коли кодується відсоток, застосовується лише загалом; символи можуть бути кодовані у відсотках, не змінюючи семантику для конкретних схем, але все ж залишаються зарезервованими.


23

Щоб відповісти, що є дійсним у рядку запиту, я перевірив, які спеціальні символи замінюються хромом під час подання запиту:

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

Примітка. Це, ймовірно, не означає, що вам не слід уникати символів, які не замінилися під час створення URI для посилань. Наприклад, часто рекомендується не використовувати ~в URI через проблеми сумісності, але це все-таки дійсний символ.

Іншим прикладом може бути знак плюс, який є дійсним, але зазвичай трактується як закодований бланк, коли сервер отримує його як частину запиту. Таким чином, він повинен бути закодований, навіть якщо він дійсний, коли його мета - представляти плюс, а не пробіл.

Отже, щоб відповісти, що слід закодувати: Недійсні символи та символи, які ви хочете дослідити буквально, але мають особливе значення або можуть спричинити проблеми на кінці сервера.


Чи /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2дійсний параметр запиту?
Суміт Джайн

@SumitJain Ні, оскільки #не може відображатися всередині частини запиту URI як є. Вам потрібно буде закодувати його як %23, щоб URI мав бути /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232.
Дай

10

Просто використовуйте ?q=1+2+3

Я відповідаю тут на четверте запитання :), яке не задавав, але все починалося з: як мені передати список чисел, відокремлених комами? Мені здається, найкращим підходом є просто передавати їх, розділені пробілом, де пробіли будуть кодуватися у формі url-форми +. Чудово працює, доки ви знаєте, що значення в списку не містять пробілів (щось число, як правило, не робить).


Хоча це має бути коментар (оскільки він не відповідає на питання), дякую. +У конкретному випадку має ще більший сенс те, що я шукав використання кома.
Gajus

6

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

це дійсна URL-адреса?

Так. ;Зарезервований, але не в RFC. Контекст, що визначає цей компонент, - це визначення типу application/x-www-form-urlencodedмедіа, що є частиною стандарту HTML (розділ 17.13.4.1 ). Зокрема, підлітка, прихована у розділі B.2.2 :

Ми рекомендуємо, щоб реалізатори сервера HTTP, і зокрема, CGI-реактори підтримували використання ";" замість "&", щоб врятувати авторам проблему втечі символів "&" таким чином.

На жаль, багато популярних сценаріїв сценаріїв на стороні сервера, включаючи ASP.NET, не підтримують це використання.


Тож як ?q=1;q=2;q=3запит дійсний, він неоднозначний: деякі рамки на стороні сервера будуть читати це, щоб означати { q: '1;q=2;q=3' }, інші можуть робити це схоже { q: {'1', '2', '3'}}.
Нас Банов

1
Так. І що ще гірше, зараз HTML5 не містить мови про те ;, що означає, що HTML4 та HTML5 несумісні. Тьху, небезпеки ненормативної мови у специфічному документі ...
bobince

@NasBanov І все ж інші (наприклад, PHP) трактуватимуть це як{ q: 3 }
Ніколас Шенкс

1
@NicholasShanks - там, де бере участь PHP, усі ставки знижуються! :)
Нас Банов

1

Я хотів би зазначити, що page.html?q=1&q=2&q=3це також дійсна URL-адреса. Це абсолютно законний спосіб вираження масиву в рядку запиту. Ваша технологія сервера визначатиме, як саме це представлено.

У Classic ASP ви перевіряєте Response.QueryString("q").Countта використовуєте Response.QueryString("q")(0)(і (1) та (2)).

Зауважте, що ви бачили це і на своєму ASP.NET (я думаю, це було не призначено, але дивіться):

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

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

Зауважте, що крапка з комою ігнорується, тому ви aвизначили двічі, і ви отримали її значення двічі, розділене комою. Використання всіх амперсандів Default.aspx?a=1&a=2&b=1&a=3дасть a"1,2,3". Але я впевнений, що існує метод отримання кожного окремого елемента, якщо самі елементи містять коми. Просто властивість за замовчуванням неіндексованого QueryString об'єднує підцінні значення разом з роздільниками коми.


1

У мене було те саме питання. URL-адреса, яка була гіперпосилана, була стороною URL-адресою і очікувала переліку параметрів у форматі page.html?q=1,2,3ТОЛЬКО, а URL-адреса page.html?q=1%2C2%2C3не працювала. Мені вдалося змусити його працювати за допомогою JavaScript. Можливо, це не найкращий підхід, але ви можете ознайомитись з рішенням тут, якщо це комусь допоможе.


-3

Якщо ви надсилаєте кодовані символи у файл FLASH / SWF , вам слід ВИКОРИСТИТИ символу двічі !! (через парсер Flash)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.