Что действительное, а что нет в запросе URI?

Фон (вопрос ниже)

Я искал это взад и вперед, читая RFC и SO вопросы, пытаясь взломать это, но у меня все еще нет джек.

Итак, я думаю, мы просто голосуем за "лучший" ответ и что он, или?

В основном это сводится к этому.

3.4. Компонент запросов

Компонент запроса представляет собой строку информации, которая должна быть интерпретирована ресурсом.

query = *uric

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

Первое, что поражает меня, - это то, что * 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>

Внутри < путь > и <searchpart> компоненты, "/" , ";", "?" зарезервированы. Символ "/" может использоваться в HTTP для обозначения иерархической структуры.

Я интерпретирую это, по крайней мере, в отношении URL-адресов HTTP, которые RFC 1738 заменяет RFC 2396. Поскольку в запросе URI нет понятия строки запроса, интерпретация зарезервированных данных на самом деле не позволяет мне определять строки запроса, м, которые раньше делали.

Вопрос

Это все началось, когда я хотел передать список чисел вместе с запросом другого ресурса. Я не очень много думал об этом и просто передал его как значения, разделенные запятой. К моему удивлению, хотя запятая была сбежала. Запрос page.html?q=1,2,3, закодированный в page.html?q=1%2C2%2C3, работает, но он уродлив и не ожидал этого. Это когда я начал проходить через RFC.

Мой первый вопрос - просто, нужны ли кодирующие запятые?

Мой ответ, согласно RFC 2396: да, согласно RFC 1738: no

Позже я нашел связанные сообщения о прохождении списков между запросами. Где подход csv был сбалансирован как плохой. Вместо этого появилось (не видели этого раньше).

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

Мой второй вопрос, является ли это допустимым URL?

Мой ответ, согласно RFC 2396: нет, согласно RFC 1738: no (; зарезервировано)

У меня нет проблем с передачей 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, конечно, не является эталонной реализацией, но пока не подвела меня.

Но самое главное - мой третий вопрос - где спецификация для этого? и что бы вы сделали или в этом случае не делали?

Ответ 1

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

Текущий стандарт для общих URI RFC 3986, который имеет это сказать:

2.2. Зарезервированные символы

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

   reserved    = gen-delims / sub-delims

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

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

3.3. Компонент пути

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

3.4 Компонент запроса

[...]  
      query       = *( pchar / "/" / "?" )

Таким образом, запятые явно разрешены в строках запроса и должны быть экранированы только в данных, если определенные схемы определяют его как разделитель. В схеме HTTP не используется запятая или точка с запятой в качестве разделителя в строках запроса, поэтому их не нужно избегать. Независимо от того, соответствуют ли браузеру этому стандарту, другое дело.

Использование CSV должно отлично работать для строковых данных, вам просто нужно следовать стандартным соглашениям CSV и котировать данные или избегать запятых с обратной косой чертой.

Как и для RFC 2396, он также допускает неэкранированные запятые в строках HTTP-запроса:

2.2. Зарезервированные символы

Многие URI включают в себя компоненты, состоящие или ограниченные определенными  специальные символы. Эти символы называются "зарезервированными", поскольку  их использование в компоненте URI ограничено их зарезервированными  цель. Если данные для компонента URI будут конфликтовать с  зарезервированной цели, тогда конфликтующие данные должны быть экранированы до  формирование URI.

Так как запятые не имеют зарезервированной цели по схеме HTTP, они не должны быть экранированы в данных. Замечание из § 2.3 о зарезервированных символах - это те, которые изменяют семантику, когда процентное кодирование применяется только в целом; символы могут быть закодированы в процентах без изменения семантики для конкретных схем и, тем не менее, зарезервированы.

Ответ 2

Просто используйте ?q=1+2+3

Я отвечаю на четвертый вопрос:), который не спрашивал, но все началось с: как мне передать список чисел a-la значений, разделенных запятыми? Кажется, лучший подход - просто передать их пространственно-разделенные, где пробелы будут закодированы в форме +. Отлично работает, так как вы знаете, что значения в списке не содержат пробелов (что-то не имеет значения).

Ответ 3

Чтобы ответить на то, что действительно в строке запроса, я проверил, какие специальные символы заменяются хром при выполнении запроса:

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 из-за проблем с совместимостью, но он по-прежнему является допустимым символом.

Другим примером может быть знак плюса, который действителен, но обычно рассматривается как закодированный пустой, когда сервер принимает его как часть запроса. Таким образом, он должен быть закодирован, даже если он действителен, когда он предназначен для представления плюса, а не пробела.

Итак, чтобы ответить на то, что должно быть закодировано: недопустимые символы и символы, которые вы хотите обрабатывать буквально, но имеют особое значение или могут вызвать проблемы на сервере.

Ответ 4

page.html д = 1;? Д = 2; д = 3

- это действительный URL?

Да. ; зарезервирован, но не RFC. Контекстом, определяющим этот компонент, является определение типа носителя application/x-www-form-urlencoded, который является частью стандарта HTML (раздел 17.13.4.1). В частности, скрытая заметка, скрытая в разделе B.2.2:

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

К сожалению, многие популярные серверные сценарии, включая ASP.NET, не поддерживают это использование.

Ответ 5

Хотелось бы отметить, что page.html?q=1&q=2&q=3 является правильным URL-адресом. Это вполне законный способ выражения массива в строке запроса. Ваша серверная технология определит, как именно это представлено.

В классическом 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, которое объединяет подтаблицы вместе с разделителями запятой.

Ответ 6

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

Ответ 7

Если вы отправляете ENCODED-символы в FLASH/SWF файл, тогда вы должны ОНКОИДИТЬ символ дважды! (из-за парсера Flash)