URLEncoder.encode 의 버그(?)

Posted 2014. 5. 27. 14:37

아래와 같이 HTTPURLConnection을 이용하여 파일을 다운로드하는 개발을 한다고 할때 파일명에 공백문자가 있으면 400 오류가 발생한다.

처음엔 IIS의 문제인줄 알고 MS에 문의도 해보았으나 결국은 java의 URLEncoder클래스의 공백처리가 웹서버가 인식하는 것과 달라서 발생하는 것이었다.

 

public InputStream getHttpStreamData(String serverAddress, String postParam, String requestMethod) throws Exception {
  
  long start = System.currentTimeMillis();
  
  // 접속할 HTTP URL 파싱
  HttpURLConnection conn = null;
  InputStream is = null;
  try {
   URL url = new URL(serverAddress);
   
   // URL에 연결 및 초기화
   conn = getHttpURLConnection(url);
   conn.setRequestMethod(requestMethod);
   conn.setDoInput(true);
   conn.setUseCaches(false);

 

   if(requestMethod.equals("POST")){

    conn.setDoOutput(true);
    OutputStream out_stream = conn.getOutputStream();
    
    out_stream.write( postParam.getBytes("UTF-8") );
    out_stream.flush();
    out_stream.close();
    
   }
   
   if (conn.getResponseCode() == 200) {
     is = conn.getInputStream();
   } else {
    logger.error( url.getQuery() + " Response : \n ResponseCode is "+conn.getResponseCode()+"& ResponseMessage is "+conn.getResponseMessage());
    throw new JsonException("9998", "요청처리중 오류가 발생했습니다.");
   }
   
  } catch (Exception e) {
   logger.error( " ##################################################### ");
   logger.error("ResponseCode is [[[["+conn.getResponseCode()+"]]]]");
   logger.error("ResponseMessage is [[[["+conn.getResponseMessage()+"]]]]");
   logger.error( " ##################################################### ");
   e.printStackTrace();
   throw new JsonException("9999", e.getMessage());
  }
  
  long end = System.currentTimeMillis();
  logger.warn("#########################################################");
  logger.warn( server_addr);
  logger.warn("######## elapsed time is [[[[[ " + (end - start) + " ]]]]] ms #######");
  logger.warn("#########################################################");
  
  return is;
  
 }

 

 

이런경우는 넘겨진 URL에 공백문자가 존재할 경우  "+"로 치환된 encoding 결과를 수동으로 '%20'으로 변경해 주어야 한다.

 

fileUrl = fileUrl.substring(0, lastSlashIndex) + URLEncoder.encode(fileUrl.substring(lastSlashIndex),"UTF-8").replaceAll("\\+", "%20");

 

logger.debug("RESULT>>>>>" + fileUrl);

 

 

RFC 규약에 의하면 위의 처리는 미완성이다.

다음의 블로그 글을 참고해 보면 제대로 된 URL 인코딩을 처리하려면 몇가지 문자를 더 수동으로 처리해 주어야 한다.

 

http://blog.naver.com/PostView.nhn?blogId=jogakdal&logNo=129088614&redirect=Dlog&widgetTypeCall=true

 

위의 글에 의거 앞의 메소드는 다음과 같이 처리하도록 변경했다.

 

fileUrl = fileUrl.substring(0, lastSlashIndex) + URLEncoder.encode(fileUrl.substring(lastSlashIndex),"UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");

==> 그런데 확인해보니 오히려 이렇게 변경하면 또다른 문제가 발생하는 듯 하다. 다시 원복.

 

참고로 서버와의 통신에서 인코딩된 결과를 확인하기 위해서는 다음과 같은 유틸프로그램을 사용한다.

 

http://www.microsoft.com/en-us/download/details.aspx?id=4865

 

MS에서 제공하는 네트워크 모니터링 프로그램이다.

이 프로그램을 서버와 로컬 PC에 설치한뒤에 http에 대한 부분을 모니터링하도록 설정하고 start를 누른다.

이후부터 request, response 결과가  모니터링된다.

비슷한 유형의 프로그램이 많이 나와있으니 참고하기 바란다.