Символы, разрешенные в URL

191

Кто-нибудь знает полный список символов, которые можно использовать в GET без кодирования? В данный момент я использую AZ az и 0-9 ... но я ищу, чтобы узнать полный список.

Меня также интересует, будет ли выпущена спецификация для грядущего добавления китайских, арабских URL-адресов (очевидно, что это сильно повлияет на мой вопрос)

отметка
источник
5
Символы, разрешенные в URI, являются либо зарезервированными, !*'();:@&=+$,/?#[]либо незарезервированными A-Za-z0-9_.~-(или символом процента %как частью кодировки процента)
Микл
1
В MySQL я использую это, REGEXP '[^]A-Za-z0-9_.~!*''();:@&=+$,/?#[%-]+'чтобы найти строку URL с плохими символами. Может быть, это полезно и для кого-то еще.
Микл
@Mikl: эта вещь вряд ли выглядит как регулярное выражение.
Йенс Мандер

Ответы:

182

Из спецификации RFC 1738 :

Таким образом, только буквенно-цифровые символы, специальные символы " $-_.+!*'()," и зарезервированные символы, используемые для их зарезервированных целей, могут использоваться без кодирования в URL-адресе.

РЕДАКТИРОВАТЬ: Как правильно указывает @Jukka K. Korpela, этот RFC был обновлен RFC 3986 . Это расширило и прояснило символы, допустимые для хоста, к сожалению, его нелегко скопировать и вставить, но я сделаю все возможное.

В первом согласованном порядке:

host        = IP-literal / IPv4address / reg-name

IP-literal  = "[" ( IPv6address / IPvFuture  ) "]"

IPvFuture   = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )

IPv6address =         6( h16 ":" ) ls32
                  /                       "::" 5( h16 ":" ) ls32
                  / [               h16 ] "::" 4( h16 ":" ) ls32
                  / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
                  / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
                  / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
                  / [ *4( h16 ":" ) h16 ] "::"              ls32
                  / [ *5( h16 ":" ) h16 ] "::"              h16
                  / [ *6( h16 ":" ) h16 ] "::"

ls32        = ( h16 ":" h16 ) / IPv4address
                  ; least-significant 32 bits of address

h16         = 1*4HEXDIG 
               ; 16 bits of address represented in hexadecimal

IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet

dec-octet   = DIGIT                 ; 0-9
              / %x31-39 DIGIT         ; 10-99
              / "1" 2DIGIT            ; 100-199
              / "2" %x30-34 DIGIT     ; 200-249
              / "25" %x30-35          ; 250-255

reg-name    = *( unreserved / pct-encoded / sub-delims )

unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"     <---This seems like a practical shortcut, most closely resembling original answer

reserved    = gen-delims / sub-delims

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

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

pct-encoded = "%" HEXDIG HEXDIG
Myles
источник
5
Косая черта @Tim является зарезервированным символом, поэтому, если он используется для его зарезервированной цели (разграничение путей, разграничение протокола ...), то он не нуждается в экранировании. В противном случае это так.
Майлз
4
Общие правила синтаксиса RFC 1738 были отменены в 1998 году.
Юкка К. Корпела
3
@Myles, STD 66 (= RFC 3986) упоминается в других ответах. Является ли содержание ответов правильным, это другой вопрос; Я не думаю, что какой-либо из ответов правильно описывает полный список.
Юкка К. Корпела
4
И вы можете добавить список незарезервированных A-Za-z0-9_.-~и зарезервированных символов в начале этого ответа. !*'();:@&=+$,/?#[]Это может сэкономить время для людей
Микл
2
@basZero Мне жаль, что вы нашли это запутанным, но полный ответ не прост. Ответ на ваш вопрос - нет, так как он является зарезервированным символом, заявленным:reserved = gen-delims / sub-delims gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
Майлз
42

Символы, разрешенные в URI, являются зарезервированными или незарезервированными (или символом процента в качестве части кодировки процента)

http://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters

говорит, что это RFC 3986 незарезервированные символы (раздел 2.3), а также зарезервированные символы (раздел 2.2), если им нужно сохранить свое особое значение. А также символ процента как часть кодировки процента.

янтарный
источник
7
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится.
Jaestevan
@jaestevan Цитата из связанного документа:The characters allowed in a URI are either reserved or unreserved (or a percent character as part of a percent-encoding)
Микл
26

Полный список из 66 незарезервированных символов находится в RFC3986, здесь: http://tools.ietf.org/html/rfc3986#section-2.3

Это любой символ в следующем наборе регулярных выражений:

[A-Za-z0-9_.\-~]
slacy
источник
2
Вы также можете использовать те, которые защищены.
Qwerty
Устаревшие RFC1738 указаны {}^\~и backtickкак небезопасные. И RFC3986 перечисляет \ как небезопасные из-за файловой системы. Это средство также {}^может быть использовано.
mgutt
Так что, если вы пытаетесь, скажем, найти конец URL-адреса в строке (что я и есть), было бы лучше пойти по устаревшим стандартам в принятом ответе ... Если вы проверяете URL-адрес, вы должны используйте набор символов в этом ответе.
ashleedawg
Осторожно, вы написали это как класс символов регулярного выражения. Обязательно экранируйте -или поместите его в начало или конец класса символов, потому что на [.-~]самом деле содержит все символы ASCII от 46 до 126.
kwl
19

Я проверил это, запросив мой веб-сайт (apache) со всеми доступными символами на моей немецкой клавиатуре в качестве параметра URL:

http://example.com/?^1234567890ß´qwertzuiopü+asdfghjklöä#<yxcvbnm,.-°!"§$%&/()=? `QWERTZUIOPÜ*ASDFGHJKLÖÄ\'>YXCVBNM;:_²³{[]}\|µ@€~

Они не были закодированы:

^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.-!/()=?`*;:_{}[]\|~

Не кодируется после urlencode():

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_

Не кодируется после rawurlencode():

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~

Примечание: до PHP 5.3.0 rawurlencode()кодируется ~из-за RFC 1738 . Но это было заменено RFC 3986, так что теперь его безопасно использовать. Но я не понимаю, почему, например {}, кодируются через, rawurlencode()потому что они не упомянуты в RFC 3986.

Дополнительный тест, который я сделал, касался автоматического связывания в почтовых текстах. Я протестировал Mozilla Thunderbird, aol.com, outlook.com, gmail.com, gmx.de и yahoo.de, и они полностью связали URL-адреса, содержащие эти символы:

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~+#,%&=*;:@

Конечно ?, он тоже был связан, но только если он использовался один раз.

Некоторые люди теперь предлагают использовать только rawurlencode()символы, но слышали ли вы когда-нибудь, что у кого-то были проблемы с открытием этих сайтов?

Звездочка
http://wayback.archive.org/web/*/http://google.com

Колон
https://en.wikipedia.org/wiki/Wikipedia:About

Плюс
https://plus.google.com/+google

При знаке, двоеточии, запятой и восклицательном знаке
https: //www.google.com/maps/place/USA/@36.2218457, ...

Из-за этого эти символы должны быть пригодны для использования без кодирования без проблем. Конечно, вы не должны использовать &;из-за последовательности кодирования, как &amp;. Эта же причина действительна для того, %что она используется для кодирования символов в целом. И так =как он присваивает значение имени параметра.

Наконец, я бы сказал, что можно использовать эти незакодированные:

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~!+,*:@

Но если вы ожидаете случайно сгенерированные URL-адреса, вы не должны их использовать .!, поскольку они отмечают конец предложения, а некоторые почтовые приложения не будут автоматически связывать последний символ URL-адреса . Пример:

Visit http://example.com/foo=bar! !
mgutt
источник
Практичный подход - хорошая работа. +
Оливер
12

От сюда

Таким образом, только буквенно-цифровые символы, специальные символы $-_.+!*'(), и зарезервированные символы, используемые для их зарезервированных целей, могут использоваться без кодирования в URL-адресе.

AdaTheDev
источник
6

RFC3986 определяет два набора символов, которые вы можете использовать в URI:

  • Зарезервированные персонажи ::/?#[]@!$&'()*+,;=

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

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

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

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

  • Незарезервированные персонажи :A-Za-z0-9-_.~

    незарезервировано = ALPHA / DIGIT / "-" / "." / "_" / "~"

    Символы, которые разрешены в URI, но не имеют зарезервированной цели, называются незарезервированными.

Cyker
источник
3

Предстоящее изменение касается китайских, арабских доменных имен, а не URI. Интернационализированные URI называются IRI и определены в RFC 3987 . Однако, сказав, что я бы рекомендовал не делать это самостоятельно, а полагаться на существующую протестированную библиотеку, поскольку существует множество вариантов кодирования / декодирования URI и того, что считается безопасным по спецификации, по сравнению с безопасным при реальном использовании (браузеры). ,

dajobe
источник
0

Если вы хотите предоставить пользователям особый опыт, вы можете использовать pushStateдля добавления широкого диапазона символов в URL браузера:

введите описание изображения здесь

var u="";var tt=168;
for(var i=0; i< 250;i++){
 var x = i+250*tt;
console.log(x);
 var c = String.fromCharCode(x);
 u+=c; 
}
history.pushState({},"",250*tt+u);
зловещий
источник