Как узнать, была ли строка уже закодирована в URL?
Как я могу проверить, была ли строка уже закодирована?
Например, если я закодирую TEST==
, Я получил TEST%3D%3D
, Если я снова закодирую последнюю строку, я получу TEST%253D%253D
Я должен был бы знать, прежде чем делать это, если он уже закодирован...
Я закодировал сохраненные параметры, и мне нужно их искать. Я не знаю для входных параметров, что они будут - кодированы или нет, поэтому я должен знать, должен ли я кодировать или декодировать их перед поиском.
7 ответов
Расшифруйте, сравните с оригиналом. Если он отличается, оригинал кодируется. Если это не отличается, оригинал не закодирован. Но все же это ничего не говорит о том, не была ли недавно декодированная версия еще не закодирована. Хорошее задание для рекурсии.
Я надеюсь, что никто не может написать quine в urlencode, иначе этот алгоритм застрянет.
Используйте regexp, чтобы проверить, содержит ли ваша строка недопустимые символы (т. Е. Символы, которые не могут быть найдены в строке, закодированной в URL, например, пробел).
Попробуйте расшифровать URL. Если результирующая строка короче оригинала, то исходный URL уже был закодирован, иначе вы можете безопасно его закодировать (либо он не закодирован, либо даже после кодирования URL остается неизменным, поэтому повторное кодирование не приведет к неправильному URL). Ниже приведен пример псевдо (вдохновленный ruby) кода:
# Returns encoded URL for any given URL after determining whether it is already encoded or not
def escape(url)
unescaped_url = URI.unescape(url)
if (unescaped_url.length < url.length)
return url
else
return URI.escape(url)
end
end
У Джоэла по программному обеспечению было решение для этого некоторое время назад - http://www.joelonsoftware.com/articles/Wrong.html
Или Вы можете добавить какой-то префикс в строки.
Проверьте свой URL на наличие подозрительных символов [1]. Список кандидатов:
WHITE_SPACE ,", < , > , { , } , | , \ , ^ , ~ , [ , ] , .
и `
Я использую:
private static boolean isAlreadyEncoded(String passedUrl) {
boolean isEncoded = true;
if (passedUrl.matches(".*[\\ \"\\<\\>\\{\\}|\\\\^~\\[\\]].*")) {
isEncoded = false;
}
return isEncoded;
}
Для фактического кодирования я продолжаю:
/questions/13188591/java-url-kodirovanie-parametrov-stroki-zaprosa/13188621#13188621
Примечание. Даже если ваш URL-адрес не содержит небезопасных символов, вы можете захотеть их применить, например, кодировку Punnycode для имени хоста. Так что еще есть много места для дополнительных проверок.
[1] Список кандидатов можно найти в разделе "небезопасных" спецификации URL-адреса на странице 2. В моем понимании "%" или "#" следует не указывать при проверке кодировки, поскольку эти символы могут встречаться в кодированном виде. URL-адреса также.
Вы не можете знать наверняка, если ваши строки не соответствуют определенному шаблону или вы не отслеживаете свои строки. Как вы сами отметили, закодированная строка также может быть закодирована, поэтому вы не можете быть на 100% уверены, глядя на саму строку.
Использование Spring UriComponentsBuilder:
import java.net.URI;
import org.springframework.web.util.UriComponentsBuilder;
private URI getProperlyEncodedUri(String uriString) {
try {
return URI.create(uriString);
} catch (IllegalArgumentException e) {
return UriComponentsBuilder.fromUriString(uriString).build().toUri();
}
}
Чтобы избежать двойного кодирования и создания ошибки (как указано в OP), мы снимаем кавычки, а затем снова цитируем, в Python это будет:
import urllib.parse
urllib.parse.unquote(str)
urllib.parse.quote(str)
Если вы хотите быть уверены, что строка закодирована правильно (если она должна быть закодирована) - просто декодируйте и кодируйте ее еще раз.
Metacode:
100%_correctly_encoded_string = encode(decode(input_string))
уже закодированная строка останется нетронутой. Некодированная строка будет закодирована. Строка, содержащая только символы, разрешенные в URL, также останется нетронутой.
Согласно спецификации ( https://tools.ietf.org/html/rfc3986) все URL-адреса ДОЛЖНЫ начинаться со схемы, за которой следует:
Поскольку в качестве разделителя между схемой и остальной частью URI требуется двоеточие, любая строка, содержащая двоеточие, не кодируется.
(Это предполагает, что вам не дадут неполный URI без какой-либо схемы.)
Таким образом, вы можете проверить, содержит ли строка двоеточие, если нет, url-кодировать ее, и если эта строка содержит двоеточие, исходная строка была закодирована URL-адресом, если нет, проверить, отличаются ли строки, и если да, еще раз urldecode, а если нет, это не правильный URI.
Вы можете упростить этот цикл, если знаете, какие схемы вы можете ожидать.
Благодаря этому ответу я закодировал функцию (язык JS), которая кодирует URL только один раз с помощьюencodeURI
поэтому вы можете вызвать его, чтобы убедиться, что он закодирован только один раз, и вам не нужно знать, закодирован ли URL-адрес.
ES6:
var getUrlEncoded = sURL => {
if (decodeURI(sURL) === sURL) return encodeURI(sURL)
return getUrlEncoded(decodeURI(sURL))
}
До ES6:
var getUrlEncoded = function(sURL) {
if (decodeURI(sURL) === sURL) return encodeURI(sURL)
return getUrlEncoded(decodeURI(sURL))
}
Вот несколько тестов, чтобы вы могли видеть, что URL-адрес кодируется только один раз:
getUrlEncoded("https://example.com/media/Screenshot27 UI Home.jpg")
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(encodeURI("https://example.com/media/Screenshot27 UI Home.jpg"))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(encodeURI(encodeURI("https://example.com/media/Screenshot27 UI Home.jpg")))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(decodeURI("https://example.com/media/Screenshot27 UI Home.jpg"))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(decodeURI(decodeURI("https://example.com/media/Screenshot27 UI Home.jpg")))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"