Как сравнить два URL в Java? - PullRequest
9 голосов
/ 23 марта 2011

Вот простая проблема - с учетом двух URL есть какой-нибудь встроенный метод или библиотека Apache, которая решает, равны ли они (логически)?1003 *

http://stackoverflow.com
http://stackoverflow.com/

Ответы [ 4 ]

11 голосов
/ 23 марта 2011

Хотя URI.equals() (а также проблемный URL.equals()) не возвращает true для этих конкретных примеров, я думаю, что это единственный случай, когда можно предположить эквивалентность (потому что в протоколе HTTP нет пустого пути).

URI http://stackoverflow.com/foo и http://stackoverflow.com/foo/ могут не считаться эквивалентными.

Возможно, вы можете использовать URI.equals(), заключенный в служебный метод, который явно обрабатывает этот конкретный случай.

3 голосов
/ 23 марта 2011

URL :: равнозначная ссылка

URL urlOne = new URL("http://stackoverflow.com");
URL urlTwo = new URL("http://stackoverflow.com/");

if( urlOne.equals(urlTwo) )
{
    // ....
}

Примечание из документов -

Два объекта URL равны, если они имеют одинаковый протоколссылки на эквивалентные хосты имеют одинаковый номер порта на хосте, один и тот же файл и фрагмент файла.

Два хоста считаются эквивалентными, если оба имени хоста могут быть преобразованы в один и тот же IP-адрес;в противном случае, если ни одно из имен хостов не может быть разрешено, имена хостов должны быть равны без учета регистра;или оба имени хоста равны нулю.

Поскольку для сравнения хостов требуется разрешение имен, эта операция является операцией блокировки.

Примечание. Известно, что определенное поведение для equals несовместимо с виртуальным хостингом вHTTP.

Итак, вместо этого вы должны предпочесть URI :: equals reference , как предложил @Joachim.

2 голосов
/ 18 мая 2017

Для вас может работать следующее: он проверяет, что 2 URL-адреса равны, позволяет указывать параметры в разных порядках и позволяет настраивать различные параметры, например:

  • Чувствителен ли регистр хоста
  • Является ли путь чувствительным к регистру
  • Учитывают ли регистр параметров строки запроса
  • Учитывают ли значения строки запроса регистр
  • Является ли схема чувствительной к регистру

Вы можете проверить это так:

class Main {

  public static void main(String[] args) 
  {
      UrlComparer urlComparer = new UrlComparer();

      expectResult(false, "key a case different", urlComparer.urlsMatch("//test.com?A=a&B=b", "//test.com?a=a&b=b"));
      expectResult(false, "key a case different", urlComparer.urlsMatch("https://WWW.TEST.COM?A=1&b=2", "https://www.test.com?b=2&a=1"));
      expectResult(false, "key a value different", urlComparer.urlsMatch("/test?a=2&A=A", "/test?a=A&a=2"));
      expectResult(false, "key a value different", urlComparer.urlsMatch("https://WWW.TEST.COM?A=a&b=2", "https://www.test.com?b=2&A=1"));
      expectResult(false, "null", urlComparer.urlsMatch("/test", null));
      expectResult(false, "null", urlComparer.urlsMatch(null, "/test"));
      expectResult(false, "port different", urlComparer.urlsMatch("//test.com:22?A=a&B=b", "//test.com:443?A=a&B=b"));
      expectResult(false, "port different", urlComparer.urlsMatch("https://WWW.TEST.COM:8443", "https://www.test.com"));
      expectResult(false, "protocol different", urlComparer.urlsMatch("http://WWW.TEST.COM:2121", "https://www.test.com:2121"));
      expectResult(false, "protocol different", urlComparer.urlsMatch("http://WWW.TEST.COM?A=a&b=2", "https://www.test.com?b=2&A=a"));
      expectResult(true, "both null", urlComparer.urlsMatch(null, null));
      expectResult(true, "host and scheme different case", urlComparer.urlsMatch("HTTPS://WWW.TEST.COM", "https://www.test.com"));
      expectResult(true, "host different case", urlComparer.urlsMatch("https://WWW.TEST.COM:443", "https://www.test.com"));
      expectResult(true, "identical urls", urlComparer.urlsMatch("//test.com:443?A=a&B=b", "//test.com:443?A=a&B=b"));
      expectResult(true, "identical urls", urlComparer.urlsMatch("/test?a=A&a=2", "/test?a=A&a=2"));
      expectResult(true, "identical urls", urlComparer.urlsMatch("https://www.test.com", "https://www.test.com"));
      expectResult(true, "parameter order changed", urlComparer.urlsMatch("https://www.test.com?a=1&b=2&c=522%2fMe", "https://www.test.com?c=522%2fMe&b=2&a=1"));
      expectResult(true, "parmeter order changed", urlComparer.urlsMatch("https://WWW.TEST.COM?a=1&b=2", "https://www.test.com?b=2&a=1"));
    }

    public static void expectResult(boolean expectedResult, String msg, boolean result)
    {
      if (expectedResult != result)
        throw new RuntimeException(msg);
    }
}

UrlComparer.java

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;

public class UrlComparer
{
    private boolean hostIsCaseSensitive = false;
    private boolean pathIsCaseSensitive = true;
    private boolean queryStringKeysAreCaseSensitive = true;
    private boolean queryStringValuesAreCaseSensitive = false;
    private boolean schemeIsCaseSensitive = false;

    public boolean urlsMatch(String url1, String url2)
    {
        try
        {
            if (Objects.equals(url1, url2))
                return true;

            URI uri1 = new URI(url1);
            URI uri2 = new URI(url2);

            // Compare Query String Parameters
            Map<String, String> mapParams1 = getQueryStringParams(uri1);
            Map<String, String> mapParams2 = getQueryStringParams(uri2);
            if (!mapsAreEqual(mapParams1, mapParams2, getQueryStringValuesAreCaseSensitive()))
                return false;

            // Compare scheme (http or https)
            if (!stringsAreEqual(uri1.getScheme(), uri2.getScheme(), getSchemeIsCaseSensitive()))
                return false;

            // Compare host
            if (!stringsAreEqual(uri1.getHost(), uri2.getHost(), getHostIsCaseSensitive()))
                return false;

            // Compare path
            if (!stringsAreEqual(uri1.getPath(), uri2.getPath(), getPathIsCaseSensitive()))
                return false;

            // Compare ports
            if (!portsAreEqual(uri1, uri2))
                return false;

            return true;
        }
        catch (Exception e)
        {
            return false;
        }
    }

    protected Map<String, String> getQueryStringParams(URI uri)
    {
        Map<String, String> result = getListAsMap(URLEncodedUtils.parse(uri, "UTF-8"), getQueryStringKeysAreCaseSensitive());

        return result;
    }

    protected boolean stringsAreEqual(String s1, String s2, boolean caseSensitive)
    {
        // Eliminate null cases
        if (s1 == null || s2 == null)
        {
            if (s1 == s2)
                return true;

            return false;
        }

        if (caseSensitive)
        {
            return s1.equals(s2);
        }

        return s1.equalsIgnoreCase(s2);
    }

    protected boolean mapsAreEqual(Map<String, String> map1, Map<String, String> map2, boolean caseSensitiveValues)
    {
        for (Map.Entry<String, String> entry : map1.entrySet())
        {
            String key = entry.getKey();
            String map1value = entry.getValue();
            String map2value = map2.get(key);

            if (!stringsAreEqual(map1value, map2value, caseSensitiveValues))
                return false;
        }
        for (Map.Entry<String, String> entry : map2.entrySet())
        {
            String key = entry.getKey();
            String map2value = entry.getValue();
            String map1value = map2.get(key);

            if (!stringsAreEqual(map1value, map2value, caseSensitiveValues))
                return false;
        }

        return true;
    }

    protected boolean portsAreEqual(URI uri1, URI uri2)
    {
        int port1 = uri1.getPort();
        int port2 = uri2.getPort();

        if (port1 == port2)
            return true;

        if (port1 == -1)
        {
            String scheme1 = (uri1.getScheme() == null ? "http" : uri1.getScheme()).toLowerCase();
            port1 = scheme1.equals("http") ? 80 : 443;
        }
        if (port2 == -1)
        {
            String scheme2 = (uri2.getScheme() == null ? "http" : uri2.getScheme()).toLowerCase();
            port2 = scheme2.equals("http") ? 80 : 443;
        }

        boolean result = (port1 == port2);

        return result;
    }

    protected Map<String, String> getListAsMap(List<NameValuePair> list, boolean caseSensitiveKeys)
    {
        Map<String, String> result;

        if (caseSensitiveKeys)
        {
            result = new HashMap<String, String>();
        }
        else
        {
            result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
        }

        for (NameValuePair param : list)
        {
            if (caseSensitiveKeys)
            {
                if (!result.containsKey(param.getName()))
                    result.put(param.getName(), param.getValue());
            }
            else
            {
                result.put(param.getName(), param.getValue());
            }
        }

        return result;
    }

    public boolean getSchemeIsCaseSensitive()
    {
        return schemeIsCaseSensitive;
    }

    public void setSchemeIsCaseSensitive(boolean schemeIsCaseSensitive)
    {
        this.schemeIsCaseSensitive = schemeIsCaseSensitive;
    }

    public boolean getHostIsCaseSensitive()
    {
        return hostIsCaseSensitive;
    }

    public void setHostIsCaseSensitive(boolean hostIsCaseSensitive)
    {
        this.hostIsCaseSensitive = hostIsCaseSensitive;
    }

    public boolean getPathIsCaseSensitive()
    {
        return pathIsCaseSensitive;
    }

    public void setPathIsCaseSensitive(boolean pathIsCaseSensitive)
    {
        this.pathIsCaseSensitive = pathIsCaseSensitive;
    }

    public boolean getQueryStringKeysAreCaseSensitive()
    {
        return queryStringKeysAreCaseSensitive;
    }

    public void setQueryStringKeysAreCaseSensitive(boolean queryStringKeysAreCaseSensitive)
    {
        this.queryStringKeysAreCaseSensitive = queryStringKeysAreCaseSensitive;
    }

    public boolean getQueryStringValuesAreCaseSensitive()
    {
        return queryStringValuesAreCaseSensitive;
    }

    public void setQueryStringValuesAreCaseSensitive(boolean queryStringValuesAreCaseSensitive)
    {
        this.queryStringValuesAreCaseSensitive = queryStringValuesAreCaseSensitive;
    }

}
0 голосов
/ 23 марта 2011

sameFile

public boolean sameFile (URL other) Сравнивает два URL,

, исключая компонент фрагмента.Возвращает true, если этот URL и другой аргумент равны без учета компонента фрагмента.

Параметры: other - URL для сравнения.Возвращает: true, если они ссылаются на один и тот же удаленный объект;иначе false.

также перейдите по этой ссылке

http://download.oracle.com/javase/6/docs/api/java/net/URL.html#sameFile(java.net.URL)

Поскольку я не могу добавить комментарий, браузер выдает ошибку Javascript.поэтому я добавляю свой комментарий здесь.извините за неудобства.

// это то, что я предложил

>URL url1 = new URL("http://stackoverflow.com/foo");

>URL url2 = new URL("http://stackoverflow.com/foo/");

>System.out.println(url1.sameFile(url2));

// this is suggested by Joachim Sauer 
>URI uri = new URI("http://stackoverflow.com/foo/");
>System.out.println(uri.equals("http://stackoverflow.com/foo"));

// Both are giving same result

так что Йоахим Зауэр проверил один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...