[Java] URLConnection & HttpURLConnection
- -
[Java] URLConnection & HttpURLConnection
1위 부터 20위 까지 가져와 보도록 하자 ( 30위 까지도 들어가 있더라)
※ URLConnection 클래스
- 사용자 인증이나 보안이 설정되어 있지 않은 웹서버에 접속하여 파일 등을 다운로드하는데 많이 사용한다.
- URLConnection은 리소스에 연결하기 전에 구성 되어야 한다.
- URLConnection 인스턴스는 재사용 될 수 없다. 각 리소스에 대한 커넥션 마다 다른 인스턴스를 사용해야 한다.
- 스펙 및 Method 참고
URLConnection (Java Platform SE 7)
http://docs.oracle.com/javase/7/docs/api/java/net/URLConnection.html
※ HttpURLConnection 클래스
- 스펙 및 Method 참고
HttpURLConnection (Java Platform SE 8)
https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html
- java.net.HttpURLConnection 클래스는 URLConnection을 구현한 클래스 (java.net 클래스에서 제공하는 URL 요청을 위한 클래스)
- URLConnection은 웹을 통해 데이터를 주고 받는데 사용된다. (RFC 2616을 따름)
- 데이터의 타입이나 길이는 거의 제한이 없다.
- 주로 미리 길이를 알지 못하는 스트리밍 데이터를 주고 받는데 사용된다.
- http URL을 처리할 때 도움이 되는 몇 가지 추가적인 메서드를 가지고 있다.
- 요청 방식을 확인 or 설정, redirect 여부 결정, 응답 코드와 메시지를 Read , 프록시 서버가 사용되었는지 여부 확인 메서드 등을 가지고 있다.
- 다양한 HTTP 응답 코드에 해당하는 상수 값들이 정의되어있다.
- URLConnection 클래스의 getPermission() 메서드를 오버라이드해놓았다.
★ URLConnection 클래스와 마찬가지로 생성자가 protected로 선언되어있기 때문에 기본적으로는 개발자가 직접 HttpURLConnection 객체를 생성할 수 없다.
하지만 http URL을 사용하는 URL 객체의 openConnection() 메서드가 리턴하는 URLConnection 객체는 HttpURLConnection의 인스턴스가 될 수 있기 때문에 리턴된 URLConnection을
다음처럼 HttpURLConnection으로 캐스팅해서 사용한다.
ex )
URL u = new URL("http://www.naver.com");
HttpURLConnection http = (HttpURLConnection) u.openConnection();
▶ 요청 방식 설정
- HttpURLConnection은 기본적으로 GET 메서드를 사용.
- setRequestMethod() 메서드를 사용해서 메서드 변경 가능.
- 요청방식은 대문자로 전달해야 한다.
- 지정된 요청 방식 이외의 파라미터 전달시 java.net.ProtocolException이 발생.
- Method
public void setRequestMethod(String method)
- 요청 메서드 종류
1. HEAD
- 문서의 헤더 정보만 요청한다.
ex)
import java.io.IOException;
import java.net.*;
public class HeaderGetMethod {
public static void main(String[] args) {
String domain = "http://www.naver.com";
try {
URL u = new URL(domain);
HttpURLConnection http = (HttpURLConnection) u.openConnection();
http.setRequestMethod("HEAD");
System.out.println(http.getHeaderFields());
} catch (MalformedURLException e) {
System.out.println(domain+" is not a URL I understand");
} catch (IOException e) {
}
}
}
2. GET
- 웹 서버로부터 리소스를 가져온다.
3. POST
- 폼에 입력된 내용을 서버로 전송한다.
4. DELETE
- 웹 서버의 리소스를 지운다.
- 대부분의 서버는 기본적으로 DELETE를 허용하지 않거나 인증을 요구한다.
- 서버는 이 요청을 거절하거나 인증을 요청할 수 있으며, 허용하는 경우에도 응답은 구현에 따라 차이가 있다.
- 서버설정에 따라 파일을 지우기, 휴지통으로 이동, 파일을 읽을 수 없도록 표시 하는 등의 행위를 하게 된다.
5. put
- 웹 서버로 리소스를 전송한다.
- PUT 요청도 파일을 지울 때와 마찬가지로 보통 사용자 인증을 요구하며, PUT 메서드를 지원하도록 설정해줘야 한다.
6. OPTIONS
- 특정 URL에 대해 지원되는 요청 메서드의 목록을 리턴한다.
- 요청 URL이 *인 경우 헤당 요청의 대상은 서버에 있는 하나의 특정 URL이 아니라 서버 전체에 적용된다는 것을 의미한다.
7. TRACE
- 요청을 추적한다.
- 클라이언트가 보낸 요청이 클라이언트와 서버 사이에 있는 프록시 서버에서 변경되었는지를 확인할 필요가 있는 경우 등에 쓰임
▶ 서버와 연결 해제
- HTTP 1.1은 단일 TCP 소켓을 사용해서 다수의 요청과 응답을 처리할 수 있는 Keep-Alive(HTTP 연결 재사용)를 지원한다.
하지만 Keep-Alive를 사용하면 서버가 클라이언트에게 데이터의 마지막 바이트를 전송한 후에도 연결을 쉽게 닫을 수 없다는 문제가 발생.
이때 타임아웃(하단에 상세하게 설명)을 설정하여 특정 시간 동안 활동이 없으면 연결을 종료하는 방법을 사용할 수도 있다.
위의 방법 보다는 클라이언트가 작업이 끝났을 때 스스로 연결을 종료하는 것이 바람직 하다.
- HttpURLConnection 클래스는 HTTP Keep-Alive 기능을 명시적으로 끄지 않는 한 기본적으로 지원한다.
즉 HttpURLConnection 클래스는 서버가 연결을 종료하기 전에 동일한 클라이언트에서 다시 연결할 경우 기존에 연결된 소켓을 재사용하는데,
이때 disconnect() 메서드는 특정 호스트와의 대화가 끝난 시점에 클라이언트가 서버와의 연결을 끊을 수 있도록 한다.
- 메서드 : public abstract void disconnect()
이 메서드를 호출하면 그 시점에 해당 연결을 아직 열고 있는 스트림이 있을 경우 해당 스트림을 종료시킨다.
그러나 반대로 스트림을 닫는다고 해서 연결을 닫거나 끊지는 않는다.
▶ 타임 아웃 설정 관련 내용 요약
- timeout (URLConnection은 두가지 타임아웃을 제공, 기본적인 동작은 타임아웃이 안된다.)
1. connect timeout
Method : public void setConnectTimeout(int timeout)
Parameters : timeout - an int that specifies the connect timeout value in milliseconds
- 밀리 세컨드 단위로 설정한다.
- 타임 아웃이 경과하면 java.net.SocketTimeoutException 발생.
- 타임 아웃이 0이면 무한 타임 아웃으로 해석.
Method : public int getConnectTimeout()
Returns: an int that indicates the connect timeout value in milliseconds
- 접속 타임 아웃의 설정을 돌려준다.
- 0을 반환하면 옵션 비활성화됨을 뜻함. (즉, 무한대 시간 초과).
2. read timeout
Method : public void setReadTimeout(int timeout)
Parameters: timeout - an int that specifies the timeout value to be used in milliseconds
- 밀리 세컨드 단위로 지정된 타임 아웃으로 설정.
- 0이 아닌 값은 입력 스트림에서 읽을 때 초과되는 시간을 지정한다.
- 타임 아웃 발생시 java.net.SocketTimeoutException가 발생.
- 타임 아웃이 0이면 무한 타임 아웃으로 해석된다.
Method : public int getReadTimeout()
Returns: an int that indicates the read timeout value in milliseconds
- read 타임 아웃에 대한 설정 반환.
- 0 반환하면 옵션 비활성화됨을 뜻함. (즉, 무한대 시간 초과).
▶ 서버 응답 처리하기
int getResponseCode()
public String getResponseMessage()
1) 응답 코드와 응답 메시지를 리턴받을 수 있다.
ex) 성공 케이스
String domain = "http://google.co.kr";
try {
URL u = new URL(domain);
HttpURLConnection con = (HttpURLConnection) u.openConnection();
System.out.println("응답코드 : " + con.getResponseCode());
System.out.println("응답메세지 : " + con.getResponseMessage());
} catch (MalformedURLException e) {
System.out.println(domain+" is not a URL I understand");
} catch (IOException e) {
}
응답코드 : 200
응답메세지 : OK
ex) 페이지 없음
String domain = "http://google.co.kr/GGGGGGGGGGGG";
try {
URL u = new URL(domain);
HttpURLConnection con = (HttpURLConnection) u.openConnection();
System.out.println("응답코드 : " + con.getResponseCode());
System.out.println("응답메세지 : " + con.getResponseMessage());
} catch (MalformedURLException e) {
System.out.println(domain+" is not a URL I understand");
} catch (IOException e) {
}
HTTP 1.0은 16가지의 응답 코드를 정의했고, HTTP 1.1은 이를 확장해서 40가지의 응답 코드를 정의한다.
이 응답 코드 중에서 404와 같이 잘 알려진 코드는 숫자만으로도 충분히 의미를 전달할 수 있지만 많은 다른 코드들은 우리에게 친숙하지 않다.
HttpURLConnection 클래스는 일반적인 응답코드 36개를 HttpURLConnection.OL 또는 HttpURLConnection.NOT_FOUND 같은 상수로 제공한다.
2) 에러 발생시 관련 데이터 Read
public InputStream getErrorStream()
- 에러 발생 시에 리턴되는 데이터는 getErrorStream() 메서드를 통해 얻을 수 있다.
- 이 메서드는 에러가 발생하지 않았거나 리턴 데이터가 없는 경우에는 null을 리턴한다.
- getErrorStream() 메서드는 일반적으로 getInputStream()이 실패한 경우의 catch 블록에서 사용한다.
3) 리다이렉트
- 응답코드 300번대는 모두 일종의 리다이렉트(방향 재지정)를 의미한다.
- 300번대 응답 코드를 받은 대부분의 브라우저는 해당 리소스의 새로운 위치로부터 자동으로 요청하여 읽지만
이 방법은 사용자에게 아무런 통보 없이 신뢰할 수 없는 사이트로 이동시킬 가능성이 있기 때문에 보안 상 문제가 될 가능성이 있다.
그래서 기본적으로는 HttpURLConnection은 리다이렉트를 따라갈지언정 그 여부를 결정할 수 있는 static 메서드가 2개 제공된다.
public static boolean getFollowRedirects()
- 메서드는 리다이렉트가 허용된 경우 true를, 그렇지 않은 경우에는 false를 리턴
public static void setFollowRedirects(boolean follow)
- 호출 시 true를 파라미터로 전달하면 리다이렉트를 따라가게 만들고, false를 전달하면 따라가지 않게 만든다.
- 두 메서드는 static이기 때문에 이 메서드가 호출된 이후에 생성된 모든 HttpURLConnection 객체에 영향을 준다.
다만 setFollowRedirects() 메서드는 보안 관리자가 변경을 허가하지 않을 경우 SecurityException 예외를 발생시킨다.
그래서 자바는 개별 인스턴스 단위로 리다이렉트를 설정하는 다음 두 개의 메서드를 제공한다.
public boolean getInstanceFollowRedirects()
public void setInstanceFollowRedirects(boolean followRedirects)
인스턴스의 경우에는 setInstanceFollowRedirects() 메서드가 호출되지 않았다면 setFollowRedirects()에 의해 설정된 동작을 따른다.
▶ 스트리밍
- HTTP 서버로 전송되는 모든 요청에는 HTTP 헤더가 포함된다.
- 헤더는 요청 본문보다 먼저 전송되기 때문에 헤더를 작성하기 위해 요청 본문의 길이를 먼저 알아야 하는 경우 문제가 발생한다.
자바는 이 상황을 HttpURLConnection에서 얻은 OutputStream에 쓴 모든 데이터를 스트림이 닫힐 때까지 캐시하는 방법으로 해결한다.
즉 스트림이 닫히는 시점에 요청 본문의 크기를 계산해서 이 정보로 Content-length 헤더를 작성하는 것이다.
결국 매우 긴 폼의 경우 정상 동작 하지 않거나 매우 느리다.
이에 대한 해결책.
1. 전송할 데이터의 크기를 알 수 없는 경우(청크 분할 전송 인코딩 모드)
- 전송할 데이터의 크기를 알 수 없는 경우에는 청크 분할 전송 인코딩(chunked transfer encoding)을 사용할 수 있다.
- 청크 분할 전송 인코딩에서 요청 본문은 몇 개의 조각으로 분할되어 전송된다.
- 각 조각은 자신의 컨텐츠 길이를 가지고 있고, 이 방법을 사용하기 위해서는 URL을 연결하기 전에 setChunkedStreamingMode() 메서드를 호출하면서
원하는 청크의 크기를 파라미터로 전달해야 한다.
public void setChunkedStreamingMode(int chunkLength)
- 청크 분할 전송 인코딩은 리다이렉션과 인증이 필요한 사이트에서 문제가 된다.
- 만약 우리가 청크로 분할된 파일을 리다이렉트된 URL이나 패스워드 인증을 요구하는 사이트에 전송할 경우에는 HttpRetryException이 발생.
2. 요청 데이터의 크기를 미리 알 수 있는 경우(고정 길이 스트리밍 모드)
- 요청 데이터의 크기를 미리 알 수 있는 경우에는 이 정보를 HttpURLConnection 객체에 전달해서 연결을 최적화할 수 있다.
- 데이터의 크기를 미리 전달할 경우에 자바는 해당 데이터를 네트워크로 즉시 스트리밍할 수 있기 때문이다.
- 전송할 데이터의 크기를 인자로 setFixedLengthStreamingMode() 메서드를 호출하면 된다.
- 실제 전송할 데이터의 크기가 int의 최대 크기보다 큰 경우, 자바 7 이후 버전에서는 long 타입을 대신 사용할 수 있다.
public void setFixedLengthStreamingMode(int contentLength)
public void setFixedLengthStreamingMode(long contentLength) // java 7
'2. 웹개발 > JAVA' 카테고리의 다른 글
[Java] 실수할 수 있는 날짜 형식(YYYY vs yyyy) (0) | 2020.12.30 |
---|---|
[Java] HttpsURLConnection (3) | 2020.08.20 |
[Java] java 메모리 구조 (0) | 2018.09.19 |
[Java] Eclipse 단축키 정리 (3) | 2018.07.03 |
[Java] html 제너레이션 (html 젠) (1) | 2018.07.01 |
소중한 공감 감사합니다