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

Предыстория (вопрос ниже)

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

Поэтому, я думаю, мы просто голосуем за «лучший» ответ, и все.

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

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

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

query = *uric

Внутри компонента запроса сохраняются символы «;», «/», «?», «:», «@», «&», «=», «+», «,» И «$».

Первое, что поражает меня, это то, что * uric определяется как это

uric = reserved | unreserved | escaped

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

Это, однако, несколько разъяснено пунктами, такими как

«Сдержанный» class синтаксиса выше относится к тем символам, которые разрешены в URI, но которые могут не разрешаться в определенном компоненте синтаксиса общего URI; они используются в качестве разделителей компонентов, описанных в разделе 3.

Символы в «зарезервированном» наборе не зарезервированы во всех контекстах. Набор символов, фактически зарезервированных в пределах любого данного компонента URI, определяется этим компонентом. В общем случае символ зарезервирован, если семантика URI изменяется, если символ заменен на его экранированную кодировку US-ASCII.

Этот последний отрывок чувствует себя несколько назад, но в нем четко сказано, что зарезервированный набор символов зависит от контекста. Однако 3.4 указывает, что все зарезервированные символы зарезервированы в компоненте запроса, однако единственные вещи, которые могут изменить семантику здесь, – это экранирование вопросительного знака (?), Поскольку URI не определяют концепцию строки запроса.

На данный момент я полностью отказался от RFC, но нашел RFC 1738 особенно интересным.

URL-адрес HTTP принимает форму:

http://:/?

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

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

Вопрос

Все это началось, когда я хотел передать список чисел вместе с запросом другого ресурса. Я не очень много думал об этом и просто передал его как значения, разделенные запятой. К моему удивлению, хотя запятая была сбежала. Запрос page.html?q=1,2,3 encoded превратился в 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, конечно, не является эталонной реализацией, но пока это еще не подвело.

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

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

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

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

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

  reserved = gen-delims / sub-delims

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

    sub-delims = "!"  / "$" / "&" / "'" / "(" / ")"
                / "*" / "+" / "," / ";"  знак равно 

3.3. Компонент Path

[…]

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

[…]

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

[…]

  query = * (pchar / "/" / "?") 

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

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

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

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

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

Поскольку запятые не имеют зарезервированной цели по схеме HTTP, их не нужно избегать в данных. Замечание из § 2.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 из-за проблем совместимости, но он по-прежнему является допустимым символом.

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

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

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

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

? Page.html д = 1; д = 2; д = 3

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

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

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

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

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

В classическом 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" 

Обратите внимание, что точка с запятой игнорируется, поэтому у вас есть определенное значение дважды, и вы получили ее значение дважды, разделенное запятой. Использование всех амперсандов Default.aspx?a=1&a=2&b=1&a=3 даст a «1,2,3». Но я уверен, что есть способ получить каждый отдельный элемент, если сами элементы содержат запятые. Это просто свойство по умолчанию неиндексированного QueryString, которое объединяет подтаблицы вместе с разделителями запятой.

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

Если вы отправляете ENCODED символов в FLASH / SWF- файл, вы должны ENCODE символ дважды! (из-за парсера Flash)

Interesting Posts

Android, ListView IllegalStateException: «Содержимое адаптера изменилось, но ListView не получил уведомление»

Пауза GC Ошибка после обновления Android 4.4.2

Приоритет && над ||

Временная метка с миллисекундной точностью: как сохранить их в MySQL

Установленная Java 7 в Mac OS X, но Terminal по-прежнему использует версию 6

Есть ли библиотека MSDN для Visual Studio 2010?

Установите / снимите флажок в окне datagridview

Запись QEMU загрузки виртуальной машины в файл

В чем разница между ConcurrentHashMap и Collections.synchronizedMap (Карта)?

Как сохранить историю bash во всех сессиях?

Анимация fragmentации: слайд и слайд

как приостановить и возобновить stream surfaceView

Является ли наиболее значительная десятичная цифра точностью, которая может быть преобразована в двоичную и обратно в десятичную без потери значимости 6 или 7.225?

Будет ли Java встроенный метод (ы) во время оптимизации?

MySQL выбирает оператор с CASE или IF ELSEIF? Не уверен, как получить результат

Давайте будем гением компьютера.