[Java] java.net.HttpURLConnection

BBANG-JUN·2021년 9월 2일
1

Java

목록 보기
5/6
post-thumbnail

HTTP 통신

HttpURLConnection는 HTTP 통신을 가능케 해주는 클래스이다.

HTTP란?
HyperText Transfer Protocol의 약자로 서버와 클라이언트 간 통신에 사용되는 규약이다.
소켓을 이용한 TCP/IP 통신을 기반으로 수행되지만, 거기에 HTTP 규약이 추가된 형태로 수행된다.

HttpURLConnection

HTTP requset와 response는

  • 데이터의 정보를 담는 Header
  • 데이터를 담는 Body

로 구성이 된다.

구글에 요청을 보내는 예제 코드를 확인해봅시다.

code_1...연결(connect)

String domain = "http://google.co.kr";

try{
	URL u = new URL(domain); // (1)
    	HttpURLConnection con = (HttpURLConnection) u.openConnection(); // (2)
        System.out.println(con.getResponseCode()); // 200
        System.out.println(con.getResponseMessage()); // OK
        
}catch(MalformedURLException e){
	System.out.println(e);
}catch(IOException e){
	System.out.println(e);
}

(1) URL u = new URL(domain);
String domain에 있는 주소로 URL 클래스를 생성합니다.

(2) HttpURLConnection con = (HttpURLConnection) u.openConnection();
(2-1). u.openConnection(); 을 이용해서 URLConnection 클래스를 얻고,
(2-2). (HttpURLConnection) u.openConnection(); 로 리턴된 URLConnection을 다음처럼 HttpURLConnection 형태로 캐스팅(casting) 해서 사용할 수 있게 됩니다.

URLConnection이란?

  • 웹을 통해 데이터를 주고 받는데 사용됩니다. (RFC 2616을 따름 = Http/1.1(1999) )

HttpURLconnection이란?

  • HttpURLConnection는 URLConnection을 구현한 클래스
  • java.net 클래스에서 제공하는 URL 요청을 위한 클래스
  • 데이터 타입 길이가 없습니다.
  • URLConnection와 마찬가지로 protected로 선언되어 있음으로 기본적으로 개발자가 생성이 불가능 합니다.
  • HttpURLConnection con = (HttpURLConnection) u.openConnection();
    Http URL을 사용하는 URL객체의 .openConnection() 메서드가 리턴(return)하는
    URLConnection 클래스는 HttpURLConnection의 인스턴스가 될 수 있기에
    리턴된 URLConnection을 다음처럼 HttpURLConnection으로 캐스팅해서 사용합니다.

code_2...세팅(setting)

String domain = "http://google.co.kr";


try{
	URL u = new URL(domain); 
    	HttpURLConnection con = (HttpURLConnection) u.openConnection();
        
        //con.getInputStream();
        
        /** settings **/
        //con.setDoInput(true);
        //con.setDoOutput(true);
        con.setUseCached(false);
        con.setRequestMethod("GET");  // ............(1)
        con.setReqestProperty("key","value");  // ...(2)
        con.setConnectTimeOut(1000); // .............(3)
        con.setReadTimeOut(1000);  // ...............(4)
        
        Sysout.print.out(con.getResponseCode()); // 200
        Sysout.print.out(con.getResponseMessage()); // OK
        
}catch(MalformedURLException e){
	System.out.println(e);
}catch(IOException e){
	System.out.println(e);
}

(1) con.setRequestMethod("GET");
메서드 변경이 가능하며 지정된 요청방식으로 파라미터를 전달합니다.
이외시, java.net.ProtocolException이 발생합니다.
기본적으로 HttpURLConnection은 "GET" 방식을 사용합니다.

요청방식내용
"HEAD"문서의 헤더 정보만 가져온다.
"GET"웹 서버로부터 리소스를 가져온다.
"POST"폼에 입력된 내용을 서버로 전송한다.
"DELETE"웹 서버의 리소스를 지운다.
"PUT"웹 서버로 리소스를 전달한다.
대부분의 서버는 DELETE를 허용하지 않고 인증을 요구한다.
"OPTIONS"특정 URL에 대해 지원되는 요청 메서드 목록이 리턴된다.
DELETE와 마찬가지로 인증을 요구하며, PUT 메서드를 지원하도록 설정이 필요하다.
"TRACE"요청을 추적한다.
클라이언트가 보낸 요청이 클라이언트와 서버 사이에 있는 프록시 서버에서 변경되었는지를 확인할 필요가 있을 때 쓰인다.

(2) con.setReqestProperty("key","value");
request Header 설정으로 key-value 형식으로 다양한 요청 설정이 가능하다.

(3) con.setConnectTimeOut(1000);
서버와의 연결제한 시간이다.

  • 밀리 세컨드 단위로 설정
  • 타임 아웃시, java.net.SocketTimeoutException 발생
  • 타임아웃이 0이면 무한 타임아웃으로 해석

(4) con.setReadTimeOut(1000);
서버 연결 후 데이터를 읽는 시간이다.

  • 밀리 세컨드 단위로 설정
  • 0이 아닌 값은 입력스트림에서 읽을 때 초과하는 시간을 지정
  • 타임 아웃시, java.net.SocketTimeoutException 발생
  • 타임아웃이 0이면 무한 타임아웃으로 해석

Connect Time Out 과 Read Time Out은
URL 호출 시 무한대기 상태를 방지하기 위함으로 작성된다.

code_3...인증서(SSL/TLS)

String domain = "http://google.co.kr";


try{
	URL u = new URL(domain); 
    	HttpURLConnection con = (HttpURLConnection) u.openConnection();
        
        /** settings **/
        //con.setDoInput(true);
        //con.setDoOutput(true);
        con.setUseCached(false);
        con.setRequestMethod("GET");  
        con.setReqestProperty("key","value");  
        con.setConnectTimeOut(1000);
        con.setReadTimeOut(1000);
        
        Sysout.print.out(con.getResponseCode()); 
        Sysout.print.out(con.getResponseMessage());
        
        /** SSL settings **/  // ................... (1)
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null); // Validation(검증)
        con.setSSLScoketFactory(context.getSocketFactory());
        
        /** Connect to host **/
        con.connect();
        con.setInstanceFollowRedirects(true);
        
        /** 연결여부(200)에 따른 결과대입 **/
        if(con.getResponseCode == HttpsURLConnect.HTTP_OK){
        	in = con.getInputStream();
        }else{
        	in = con.getErrorStream();
        }
        
        /** 결과 라인 수 만큼 읽기 **/
        BufferedReader reader = new BufferedReade(new InputStreamReader(in));
        while((line = reader.readLine()) != null ){
        	System.out.printf("%s\n", line);
        }
        reader.close(); // 닫기
        
}finally{
	if(reader != null){
    	reader.close();
    }
    if(con != null){
    	con.disconnect();
    }
}

(1)

SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null); // Validation(검증)
con.setSSLScoketFactory(context.getSocketFactory());

HTTP 통신을 하다보면 인증서 문제를 많이 겪을 것이다.
에러내용 : SSLHandshake Exception : ..................
원인
1. SSL 인증서가 신뢰하는 기관 인증서가 없거나 SSL/TLS 암호화 버전이 맞지 않을 경우
2. 사설 인증서이기에 인증기관 목록이 없는 경우
3. 서버/클라이언트 사이에 사용하려는 TLS 버전이 맞지 않을 때
4. TLS 통신에 사용하려는 cipher suite가 오래되거나 지원하지 않을 때(JDK1.8 부터는 sha256 사용)

해결방법
1. 시스템 프로퍼티에 수동 SSL 인증서 등록
2. 공인 인증된 인증서로 서버 인증
3. 아무 작업도 하지 않은 Trust Manager를 설치하여 우회
(3-1). 인증서를 우회하는 작업인데 보안이슈 야기, 배포 리젝발생 야기 등 문제점이 있다.

code_4...인증서 우회코드

   ...
    
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager(){
    	public java.security.cert.X509Certificate[] get AcceptedIssuers(){
    		return null;
    	}
        public void checkClientTrusted(X509Certificate[] certs, String authType){
        	return null;
        }
        public void checkServerTrusted(X509Certificate[] certs, String authType){
        	return null;
        }
    });
    
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, trustAllCerts , new java.security.SecureRandom()); 
    con.setSSLScoketFactory(context.getSocketFactory());
    
    ...

code_3 코드에서 다음과 같이 적용하면 된다. 해당 방법은 우회하는 방법이므로 추천은 안한다.

참고

profile
🔥 머릿속으로 생각하지만 말고, 행동으로 보여줘

0개의 댓글