HTTPURLCONNECTION를 사용하여 웹 페이지 액세스하기
이 글은HttpURLConnection
과 이의 서브클래스인HttpsURLConnection
을 사용하여 보안 웹 페이지에 액세스하는 방법을 보여준다. 또한 비보안 페이지(non-secure page)에서 보안 페이지(secure one)로의 리다이렉트를 쉽게 할 수 있는 방법도 볼 수 있다. HTTP 와 HTTPS에 관한 정보는HTTP 1.1 RFC 2616과HTTPS RFC 2818를 참고하기 바란다.
첫번째 예로, 주어진 URL에 접속하기 위해 다음WebPageReader
프로그램의HttpURLConnection
를 이용해 보자. 그리고 페이지의 내용을 스탠다드 아웃(standard out)에 출력하자.
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URLConnection;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class WebPageReader {
private static URLConnection connection;
private static void connect(String urlString) {
try {
URL url = new URL(urlString);
connection = url.openConnection();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void readContents() {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("usage: java WebPageReader " + "<url>");
System.exit(0);
}
connect(args[0]);
readContents();
}
}
만약 현재의 위치가 방화벽 뒤라면, 다음과 같이 설정된proxyHost
과proxyPort
변수들이 필요하다.
http.proxyHost=webcache
http.proxyPort=8080
https.proxyHost=webcache
https.proxyPort=8080
커맨드 라인에-D
플래그를 이용해서 값을 직접 입력하거나 프로그램 상에서System.setProperty()
를 호출함으로써 변수를 구할 수있다.WebPageReader
를 컴파일한 후에 이하와 같은 커맨드로 Core Java Technologies Tech Tips 홈 페이지의 내용을 열거해 볼 수 있다.
java WebPageReaderhttp://java.sun.com/developer/JDCTechTips/
URLConnection
는 추상 클래스이다. URL클래스의openConnection()
메소드는 지정된 URL을 읽을 수 있도록 적절하고 구체적인 서브클래스를 리턴한다. http나 https URL을 입력하면 이는HttpURLConnection
나HttpsURLConnection
의 서브클래스가 될 것이다. 만약 다음을openConnection(
)를 호출하는 라인에 추가하면,
System.out.println(connection.getClass());
HttpURLConnection
의 숨겨진 구현 클래스의 인스턴스를 리턴하는 커넥션(connection)을 보게 된다. 예를 들면, 다음과 같다.
class sun.net.www.protocol.http.HttpURLConnection
이와 유사하게 보안 페이지를 읽기 위해 동일한WebPageReader
코드를 사용할 수가 있다.
java WebPageReader https://today.dev.java.net
후자의 경우, 커넥션은HttpsURLConnection
의 서브클래스인HttpURLConnection
타입이라는 것을 알아야 한다. 보다 명확하게 말하자면 다음과 같은 숨어있는 구현 클래스가 있다는 것을 인식할 수 있어야 한다.
class sun.net.www.protocol.https.HttpsURLConnectionImpl
일반적으로 브라우저에 URL을 입력할 때, 이동하고자하는 페이지가 보안 페이지인지 아닌지는 알 수가 없다. 다시 말하면, today.dev.java.net 페이지를 보기 위해서는http://today.dev.java.net를입력한다. 필요하다면 브라우저가 리다이렉트할 것이고 사용자를 https://today.dev.java.net로 연결하기 위해 적절한 신호변경을 수행한다.WebPageReader
프로그램이 요청된 리다이렉션을 수행하는지를 살펴보자.
java WebPageReaderhttp://today.dev.java.net
원하는 페이지로 리다이렉트되는 대신에 다음과 같은 메시지를 보게 된다.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>301 Moved Permanently</TITLE>
</HEAD><BODY>
<H1>Moved Permanently</H1>
The document has moved
<A href="https://today.dev.java.net/" mce_href="https://today.dev.java.net/">here</A>.<P>
<HR>
<ADDRESS>
Apache/1.3.26 Server at today.dev.java.net Port 80
</ADDRESS>
</BODY></HTML>
이 정보로부터 무언가를 읽어내는 것은 어렵지만 문제는 리다이렉션에 관한 것이 아니다. URLhttp://linux.java.net으로프로그램을 실행하면, 프로그램은http://community.java.net/linux으로적절히 이를 리다이렉트하고 사용자는 원하는 컨텐츠를 볼 수가 있다. 어떤 일이 일어나는지를 자세히 살펴보려면HttpURLConnection
를 명시적으로 이용해야 한다. 스탠다드 아웃에 웹 페이지의 컨텐츠를 출력하는 코드를 삭제해서 일을 간단히 해보자.RedirectingReader
프로그램이다.
import java.net.URL;
import java.net.MalformedURLException;
import java.net.HttpURLConnection;
import java.io.IOException;
public class RedirectingReader {
private static HttpURLConnection connection;
private static void connect(String urlString) {
try {
URL url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
System.out.println(connection.getURL());
System.out.println(connection.getResponseCode() + " "
+ connection.getResponseMessage());
System.out.println(connection.getURL());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("usage: java WebPageReader " + "<url>");
System.exit(0);
}
connect(args[0]);
}
}
다음과 같이 리다이렉트하는 URL을 입력하여RedirectingReader
를 컴파일하고 실행해 보자.
java RedirectingReaderhttp://linux.java.net/
다음과 같은 출력값을 보게 될 것이다.
http://linux.java.net/200 OKhttp://community.java.net/linux/
첫번째 라인이 재빨리 나타난다. String값으로 URL을 생성하고HttpURLConnection
객체를 실행하자. 그러면http://linux.java.net를요청하는 동안에 잠깐의 멈춤이 생긴다. 페이지가 리다이렉트되는 이 시간동안 받게 되는 응답 코드와 메시지는 리다이렉트된 페이지로부터 온 것이다. 이 리다이렉트된 페이지는 출력값의 3번째 라인에 열거된다. URLurl = new URL(urlString);
아래의 라인을 추가해서 리다이렉션을 허용하지 않았을 때 발생하는 현상을 보자.
HttpURLConnection.setFollowRedirects(false);
출력값은 다음과 같다.
http://linux.java.net/302 Foundhttp://linux.java.net/
이는 302 에러가 발생했다는 것을 나타낸다. 곧 리다이렉트되지 않고 URL이 그대로 유지되었다는 것이다. 이를 처리하기 전에, 좀 전에 추가했던 라인을 지우고 리다이렉션이 다시 작동하는지를 확인하기 위해RedirectingReader
프로그램을 실행시켜보자.RedirectingReader
를 다시 한번 실행시키고,http://today.dev.java.net를 입력하자. 다음과 같은 출력값을 보게 된다.
http://today.dev.java.net301 Moved Permanentlyhttp://today.dev.java.net
위는 이 프로그램이 “Moved Permanently” 에러를 처리할 수 없어서 리다이렉트 했다는 것을 말한다. 이것이 바로 원했던 디폴트 속성이다. 보안문제 때문에 http 과 https간에는 리다이렉트할 수 없다. 어디로 리다이렉트할 것이냐하는 정보는 이 응답의 헤더 부분에 있다. 이전의 요청에 대한 전체 응답 헤더는 다음과 같다.
HTTP/1.1 301 Moved Permanently Date: Tue, 03 Feb 2004 01:38:43 GMT Server: Apache/1.3.26 (Unix) mod_ssl/2.8.10 OpenSSL/0.9.6b mod_jk/1.2.1 Location: https://today.dev.java.net/ Content-type: text/html; charset=iso-8859-1
HttpURLConnection
내의getResponseCode()
과getResponseMessage()
메소드가 이 응답의 첫번째 라인에 포함된 정보를 리턴하는 것을 본 적이 있을 것이다. 혹은getHeaderField()
메소드를 이용해서 헤더 필드의 이름에 스트링값을 넣어주어도 된다. 가령,getHeaderField(”Location”)
는 https://today.dev.java.net/값을 리턴한다.
이 글의 시작부분에서 언급했던 HTTP 1.1 과 HTTPS RFCs에서 요청과 응답 헤더의 포맷에 관해 자세히 살펴 볼 수 있다. 300 레벨 응답에서, “Location:”는 리다이렉션을 위한 위치값을 제공해야만 한다. 301나 302 에러를 발생하는지를 확인하기 위해 다음 사항을 추가하자.
private static boolean mustRedirect(int code) {
if (code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_MOVED_TEMP) {
System.out.println("Received error " + code + ", trying secure redirect");
return true;
} else
return false;
}
리다이렉트가 자동적으로 처리되지 않는다면 사용자는 301 나 302 응답 코드만을 받게 된다는 것을 기억하자. 지금까지 이것은 리다이렉트가HttpURLConnection
가 아닌HttpsURLConnection
가 필요하다는 것을 의미했다. “Location:” 필드에 제공된 정보를 따르자. 다음과 같이 새로운 정보를 이용해서 url 값과 커넥션을 재설정하자.
url = new URL("https://" + url.getHost() + url.getFile());
connection = (HttpsURLConnection) url.openConnection();
마지막으로, 웹 리더를 받기 위해 위의 모든 사항을 모으고 필요할 때 보안 페이지로 리다이렉트될 수 있도록 하자.
import javax.net.ssl.HttpsURLConnection;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.HttpURLConnection;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class RedirectingReader {
private static HttpURLConnection connection;
private static URL url;
private static void connect(String urlString) {
try {
url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
int code = connection.getResponseCode();
if (mustRedirect(code))
secureRedirect(connection.getHeaderField("Location"));
readContents();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static boolean mustRedirect(int code) {
if (code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_MOVED_TEMP) {
return true;
} else
return false;
}
private static void secureRedirect(String location) throws IOException {
System.out.println(location);
url = new URL(location);
connection = (HttpsURLConnection) url.openConnection();
}
private static void readContents() {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(connection
.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("usage: java WebPageReader " + "<url>");
System.exit(0);
}
connect(args[0]);
}
}
업데이트된RedirectingReader
를 컴파일하고 동작이 제대로 이루어지는지 확인하기 위해 몇 개의 다른 입력값을 넣어 실행해보자. 예를 들면http://today.dev.java.net와http://linux.java.net를넣어보자. 리다이렉트되지 않는 보안페이지와 비보안 페이지를 입력해서RedirectingReader
를 실행해도 동작이 적절하게 이루어져야 한다. 이제 다시 뒤로 돌아가서 최초WebReader
프로그램에 모든println()
메소드를 제거하고readContents()
를 추가할 수 있다
'Java' 카테고리의 다른 글
JSSE 1.0.3_04 설치 (0) | 2007.01.06 |
---|---|
This is README file for Jad (0) | 2006.12.15 |
I18N Messages and Logging (0) | 2006.12.07 |