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으로 대체 됨)
URLEncoder
HTTP 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
클래스는, 이름이에도 불구하고, 여기에 필요한 것을 아니다. 썬이이 클래스를 그렇게 성가신 것으로 명명 한 것은 불행합니다. URLEncoder
URL 자체를 인코딩하는 것이 아니라 매개 변수로 데이터를 전달하기위한 것입니다.
즉, "http://search.barnesandnoble.com/booksearch/first book.pdf"
URL입니다. 매개 변수는 예를 들어 "http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this¶m2=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하면 해당 매개 변수 값이 수정됩니다.
그래서 두 가지 선택이 있습니다.
-
도메인과 다른 경로에 액세스 할 수 있습니까? 그렇다면 단순히 경로를 UrlEncode 할 수 있습니다. 그러나 그렇지 않은 경우 옵션 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 이스케이프를 구현하는 코드입니다 .
