[java] Java의 HTTP URL 주소 인코딩

Java 독립형 응용 프로그램은 사용자로부터 URL (파일을 가리키는)을 가져 와서 다운로드하여 다운로드해야합니다. 내가 겪고있는 문제는 HTTP URL 주소를 올바르게 인코딩 할 수 없다는 것입니다.

예:

URL:  http://search.barnesandnoble.com/booksearch/first book.pdf

java.net.URLEncoder.encode(url.toString(), "ISO-8859-1");

나를 돌려줍니다 :

http%3A%2F%2Fsearch.barnesandnoble.com%2Fbooksearch%2Ffirst+book.pdf

하지만 내가 원하는 것은

http://search.barnesandnoble.com/booksearch/first%20book.pdf

(공간이 % 20으로 대체 됨)

URLEncoderHTTP URL을 인코딩하도록 설계되지 않은 것 같습니다 . JavaDoc에 “HTML 양식 인코딩을위한 유틸리티 클래스”라고 표시되어 있습니다. 다른 방법이 있습니까?



답변

java.net.URI의의 클래스는 도움이 될 수 있습니다; 찾은 URL 문서에서

URI 클래스는 특정 상황에서 구성 요소 필드의 이스케이프를 수행합니다. URL 인코딩 및 디코딩 관리에 권장되는 방법은 URI를 사용하는 것입니다.

다음과 같이 둘 이상의 인수가있는 생성자 중 하나를 사용하십시오.

URI uri = new URI(
    "http",
    "search.barnesandnoble.com",
    "/booksearch/first book.pdf",
    null);
URL url = uri.toURL();
//or String request = uri.toString();

(URI의 단일 인수 생성자는 잘못된 문자를 이스케이프하지 않습니다)


위의 코드로 잘못된 문자 만 이스케이프 처리합니다. 비 ASCII 문자는 이스케이프하지 않습니다 (fathi의 설명 참조).
toASCIIString메소드는 US-ASCII 문자로만 문자열을 가져 오는 데 사용할 수 있습니다.

URI uri = new URI(
    "http",
    "search.barnesandnoble.com",
    "/booksearch/é",
    null);
String request = uri.toASCIIString();

과 같은 쿼리가있는 URL http://www.google.com/ig/api?weather=São Paulo의 경우 생성자의 5 매개 변수 버전을 사용하십시오.

URI uri = new URI(
        "http",
        "www.google.com",
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();


답변

위의 답변 대부분이 부정확하다는 점에 유의하십시오.

URLEncoder클래스는, 이름이에도 불구하고, 여기에 필요한 것을 아니다. 썬이이 클래스를 그렇게 성가신 것으로 명명 한 것은 불행합니다. URLEncoderURL 자체를 인코딩하는 것이 아니라 매개 변수로 데이터를 전달하기위한 것입니다.

즉, "http://search.barnesandnoble.com/booksearch/first book.pdf"URL입니다. 매개 변수는 예를 들어 "http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this&param2=that"입니다. 매개 변수가 사용 URLEncoder됩니다.

다음 두 예는이 두 가지의 차이점을 강조합니다.

다음은 HTTP 표준에 따라 잘못된 매개 변수를 생성합니다. 앰퍼샌드 (&) 및 더하기 (+)가 잘못 인코딩되었습니다.

uri = new URI("http", null, "www.google.com", 80,
"/help/me/book name+me/", "MY CRZY QUERY! +&+ :)", null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY%20CRZY%20QUERY!%20+&+%20:)

다음은 쿼리가 올바르게 인코딩 된 올바른 매개 변수를 생성합니다. 공백, 앰퍼샌드 및 더하기 표시에 유의하십시오.

uri = new URI("http", null, "www.google.com", 80, "/help/me/book name+me/", URLEncoder.encode("MY CRZY QUERY! +&+ :)", "UTF-8"), null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY+CRZY+QUERY%2521+%252B%2526%252B+%253A%2529


답변

여기에 Android 사용자를 대상으로 한 제안을 추가하겠습니다. 외부 라이브러리를 얻지 않아도되도록 할 수 있습니다. 또한 위의 답변 중 일부에서 제안 된 모든 검색 / 대체 문자 솔루션은 위험하므로 피해야합니다.

이것을 시도하십시오 :

String urlStr = "http://abc.dev.domain.com/0007AC/ads/800x480 15sec h.264.mp4";
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
url = uri.toURL();

이 특정 URL에서 요청에 사용할 수 있도록 인코딩 된 공간이 필요하다는 것을 알 수 있습니다.

Android 클래스에서 사용할 수있는 몇 가지 기능을 활용합니다. 첫째, URL 클래스는 URL을 적절한 구성 요소로 나눌 수 있으므로 문자열 검색 / 바꾸기 작업을 수행 할 필요가 없습니다. 둘째,이 방법은 단일 문자열이 아닌 구성 요소를 통해 URI를 구성 할 때 구성 요소를 올바르게 이스케이프 처리하는 URI 클래스 기능을 활용합니다.

이 방법의 장점은 유효한 URL 문자열을 가져 와서 특별한 지식 없이도 작동시킬 수 있다는 것입니다.


답변

내가 개발하고 다른 솔루션보다 훨씬 안정적인 솔루션 :

public class URLParamEncoder {

    public static String encode(String input) {
        StringBuilder resultStr = new StringBuilder();
        for (char ch : input.toCharArray()) {
            if (isUnsafe(ch)) {
                resultStr.append('%');
                resultStr.append(toHex(ch / 16));
                resultStr.append(toHex(ch % 16));
            } else {
                resultStr.append(ch);
            }
        }
        return resultStr.toString();
    }

    private static char toHex(int ch) {
        return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
    }

    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0)
            return true;
        return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
    }

}


답변

URL이 있으면이 메소드에 url.toString ()을 전달할 수 있습니다. 이중 인코딩을 피하기 위해 먼저 디코딩합니다 (예를 들어, 공백을 인코딩하면 % 20이 발생하고 백분율 기호를 인코딩하면 % 25가 발생하므로 이중 인코딩은 공백을 % 2520으로 바꿉니다). 그런 다음 위에서 설명한대로 URL의 모든 부분을 추가하여 URI를 사용하십시오 (쿼리 매개 변수를 삭제하지 않도록).

public URL convertToURLEscapingIllegalCharacters(String string){
    try {
        String decodedURL = URLDecoder.decode(string, "UTF-8");
        URL url = new URL(decodedURL);
        URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
        return uri.toURL();
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}


답변

예, URL 인코딩은 해당 문자열을 URL로 인코딩하여 최종 목적지로 URL에 올바르게 전달됩니다. 예를 들어 http://stackoverflow.com?url=http://yyy.com을 가질 수 없습니다 . 매개 변수를 UrlEncoding하면 해당 매개 변수 값이 수정됩니다.

그래서 두 가지 선택이 있습니다.

  1. 도메인과 다른 경로에 액세스 할 수 있습니까? 그렇다면 단순히 경로를 UrlEncode 할 수 있습니다. 그러나 그렇지 않은 경우 옵션 2가 적합 할 수 있습니다.

  2. commons-httpclient-3.1을 가져 오십시오. 여기에는 URIUtil 클래스가 있습니다.

    System.out.println (URIUtil.encodePath ( ” http://example.com/x y”, “ISO-8859-1”));

URI의 경로 부분 만 인코딩하므로 원하는 것을 정확하게 출력합니다.

참고로,이 메소드가 런타임에 작동하려면 commons-codec 및 commons-logging이 필요합니다.


답변

Nitpicking : 정의에 따라 공백 문자가 포함 된 문자열은 URI가 아닙니다. 그래서 당신이 찾고있는 것은 RFC 3986 섹션 2.1에 정의 된 URI 이스케이프를 구현하는 코드입니다 .