본문 바로가기

오류 처리

서버 to 서버간 통신(http, https) 로직 개발시 체크해야할 사항

자바 내부 로직에 다른 서비스의 API를 호출해서 사용하는 로직을 개발한 적이 있었습니다. 

로컬 개발환경에서는 테스트가 잘 되었는데 통합테스트 환경에서는 작동을 안하더군요. 

그 때 오류 처리했던 사항들에 대해 공유하고자 합니다. 

 

출발지서버와 도착지서버간 http(s)를 이용해서 api 통신할 경우 조치사항

//예제소스
URL url;
HttpURLConnection connection = null;
try {
  // Create connection
  url = new URL(targetURL);
  connection = (HttpURLConnection) url.openConnection();
  ....
}

1. 출발지서버가 인터넷이 막혀있고 내부망만 허용될 경우 도착지서버 ip를 확인해서 호스트를 등록해야 합니다.

호스트를 등록하지 않았거나 방화벽이 막혀있는 경우 unknownhost 에러가 발생합니다.

2. 도착지서버 URL의 IP 확인

콘솔창에서 nslookup 명령어 이용 (아래의 경우에 두번째 Address (183.111.138.210 사용)

3. 출발지 서버에 host 등록 (서버 관리자에게 요청)

호스트파일 위치 : 리눅스 서버의 경우 일반적으로 view /etc/hosts 하면 호스트파일 확인 가능

4. 출발지서버에서 도착지서버로의 방화벽 허용 요청

방화벽 허용이 안되어 있는 경우 연결시간 초과 에러가 발생합니다. 

출발지서버IP : 1.1.1.1
도착지서버IP : 2.2.2.2
포트 : 80(일반적, http), 443(https) (다른 포트를 사용할 경우 도착지서버 담당자에게 문의해서 확인)
기간 : 2018.1.1 ~ 종료일자 없음
사유 : api 호출.....

5. 방화벽 허용되었는지 확인

telnet 도착지서버 포트번호(예 telnet 2.2.2.2 443)

방화벽 오픈이 안된 경우

//계속 대기 중이면 방화벽 오픈이 안된 상태
telnet 172.0.0.1 9999
Trying 172.0.0.1...



//방화벽 오픈 되었으나 연결 거부(상대방 API 이상)
telnet 172.0.0.1 9999
Trying 172.0.0.1...
telnet: Unable to connect to remote host: Connection refused

 

정상적으로 방화벽 오픈이 되어서 통신할 준비가 되어있는 경우

//정상적으로 방화벽 오픈이 되었고, 통신할 준비가 되어있는 경우
telnet 172.0.0.1 9999
Trying 172.0.0.1...
Connected to 172.0.0.1
Escape character is '^]'.

 

서버 To 서버 통신 로직 개발시 주의사항

서버 TO 서버 통신시 상대방 서버에서 응답이 오지 않는 경우 출발지서버까지 같이 먹통(대기상태)이 되는 경우가 발생할 수 있습니다. 그러니 아래와 같이 통신 로직에 반드시 Timeout 설정을 추가해야 합니다.

(3000 은 3초를 의미합니다.)

URL url = new URL(returnUrl);
HttpURLConnection  huc = (HttpURLConnection) url.openConnection();
...

huc.setConnectTimeout(3000); //상대방 서버 통신 오류로 인해 접속 지연시 강제로 timeout 처리;
huc.setReadTimeout(3000); //상대방 서버에서 응답이 오지 않는 경우 강제로 timeout 처리;

 

전체 로직

/**
 * 요청URL을 받아 통신하기
 * @param returnUrl
 * @return 응답결과
 * @throws Exception
 */
public String httpURLConnection(String returnUrl , String parameterInfo, String charset, HttpServletRequest request) throws IoComException {

  StringBuffer retStr = new StringBuffer();
  OutputStream os = null;
  BufferedWriter writer = null;
  BufferedReader br = null;
  
  try {
    URL url = new URL(returnUrl);
    HttpURLConnection  huc = (HttpURLConnection) url.openConnection();
    huc.setRequestMethod("POST");
    huc.setDoInput(true);
    huc.setDoOutput(true);
    huc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
    huc.setConnectTimeout(2000); //상대방 서버 통신 오류로 인해 접속 지연시 강제로 timeout 처리;
    huc.setReadTimeout(2000); //상대방 서버 통신 오류로 인해 접속 지연시 강제로 timeout 처리;

    os = huc.getOutputStream();
    writer = new BufferedWriter(new OutputStreamWriter(os, charset));
    writer.write(parameterInfo);
    writer.flush(); // 버퍼를 비워준다.
    
    // 응답받은 메시지의 길이만큼 버퍼를 생성하여 읽어들임
    br = new BufferedReader(new InputStreamReader(huc.getInputStream(),charset));
    String data;
    // 표준출력으로 한 라인씩 출력
    data = br.readLine();
    while(data != null ) {
      if(retStr.length() > 0) {
        retStr.append("\n");
      }
      retStr.append(data);
      data = br.readLine();
    }
  } catch (Exception e) {
    throw new IoComException("요청URL을 받아 통신 처리하는 도중 예기치 않은 오류 발생", e, request);
  } finally{
    // 스트림을 닫는다.
    try {
      if(os != null){
        os.close();
      }
    }catch(IOException e) {
      new IoComException("OutputStream close 처리 도중 예기치 않은 오류 발생", e);
	}

    try {
      if(writer != null){
        writer.close();
      }
    }catch(IOException e) {
      new IoComException("BufferedWriter close 처리 도중 예기치 않은 오류 발생", e);
    }
    
    try {
      if(br != null){
        br.close();
      }
    }catch(IOException e) {
      new IoComException("BufferedReader close 처리 도중 예기치 않은 오류 발생", e);
    }
  }
  
  return retStr.toString();
}