2012-09-27 4 views
4

다음 코드는 Java 6 (및 이전 버전)에서 정상적으로 작동하지만 JRE 7 (Java 7)로 업데이트 한 후 작동을 멈췄습니다./octet-stream을 -1 [Ljava.langJava 7 URL 연결 실패

응용 프로그램 :

여기 ftp://ftp-private.ncbi.nlm.nih.gov/pubchem/.fetch/96/4133257873201306969.sdf.gz

내가 얻을 출력 :

의 URL은 FTP 파일입니다. StackTraceElement; @ 5419f97c

Area: API: Networking 
Synopsis: Server Connection Shuts Down when Attempting to Read Data When http Response Code is -1 

이 어떻게 자바 7이 코드 호환 않습니다

public static void store(URL url, File targetFile){ 
    try 
    { 
    System.out.println(url); 
    URLConnection uc = url.openConnection(); 
    String contentType = uc.getContentType(); 
    System.out.println(contentType); 
    int contentLength = uc.getContentLength(); 
    System.out.println(contentLength); 
    Settings.setDownloadSize(contentLength); 
    if (contentType.startsWith("text/") || contentLength == -1) { 
     throw new IOException("This is not a binary file."); 
    } 
    InputStream raw = uc.getInputStream(); 
    InputStream in = new BufferedInputStream(raw); 
    byte[] data = new byte[contentLength]; 
    int bytesRead = 0; 
    StatusPanel.updateProgrssBar(bytesRead); 
    int offset = 0; 
    while (offset < contentLength) { 
     bytesRead = in.read(data, offset, data.length - offset); 
     if (bytesRead == -1) { 
      break; 
     } 
     offset += bytesRead; 
     StatusPanel.updateProgrssBar(offset); 
    } 
    in.close(); 

    if (offset != contentLength) { 
     throw new IOException("Only read " + offset + " bytes; Expected " + contentLength + " bytes"); 
    } 

    FileOutputStream out = new FileOutputStream(targetFile); 
    out.write(data); 
    out.flush(); 
    out.close(); 
    //StatusPanel.setStatus("File has been stored at " + targetFile.toString()); 
    //System.out.println("file has been stored at " + targetFile.toString()); 
} 

내용 길이가 -1 반환 14,그리고 여기 내 코드?

설명 : CR 6886436에 대한 버그 수정의 결과로 HTTP 프로토콜 처리기는 유효한 HTTP 상태 줄없이 응답을 보내는 서버에 대한 연결을 닫습니다. 이 문제가 발생하면 해당 연결에서 데이터를 읽으려고하면 IOException이 발생합니다.

예를 들어, 다음 코드는 문제가있다 :

public static void test() throws Exception { 

..... 
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(); 
.... 

System.out.println ("Response code: " + urlc.getResponseCode()); 

/** Following line throws java.io.IOException: Invalid Http response 
* when Response Code returned was -1 
*/ 
InputStream is = urlc.getInputStream(); // PROBLEMATIC CODE 

는이 문제를 해결하려면 getResponseCode 메서드에서 반환 값을 확인하고 적절하게 -1 값을 처리하기 위해; 새 연결을 열거 나 스트림에서 getErrorStream을 호출합니다. 비 호환성의 성질 : behavioral RFE : 7055058

getContentLength() 방법은 분명히 문제입니다.

JRE6에서는이 메서드가 값을 반환하지만 JRE7에서는 -1이 반환됩니다.

+1

서버가 반환하는 콘텐츠 길이를 확인할 가치가 있습니다. 예 : Wireshark로 네트워크를 스니핑합니다. 또한 같은 코드가 여전히 Java 6에서 작동하는지 확인 하시겠습니까? 즉 Java 7로 변경하고 작업을 중단 한 것이 우연이라는 가능성을 제거 했습니까? – DNA

+0

자바 6에서 작동합니다. 일치하지 않습니다. 나는 그것에 대해 100 % 확실하다. 추가 된 내용을보십시오.이 경우 url은 ftp입니다. HTTP가 아닙니다 .. – lochi

답변

1

Java 7's Javadoc을 기반으로하면 이러한 경우가 두 가지 원인이있을 수 있습니다.

첫 번째 가능한 원인은 콘텐츠 길이가 Integer.MAX_VALUE보다 큰 것입니다. 이 문제가 있는지 확인하려면 getContentLengthLong() 대신 int를 반환하고 길이가 Integer.MAX_VALUE보다 큰 경우 getContentLength()은 -1을 반환하므로이 메서드를 사용하십시오. 또한 Java 7부터 Java 7's URLConnection Javadoc에 명시된대로 을 getContentLength() 이상으로 사용하도록 제안했기 때문에 "대신 오랫동안 반환하므로 휴대가 편리합니다." JRE 6과 7 모두를 사용하고자한다면 Java 6 및 7 래퍼 클래스를 만들어 응용 프로그램이 URL과 상호 작용하는 데 사용하는 메서드 집합을 만듭니다. 응용 프로그램의 시작 스크립트보다 호스트에 JRE 6 또는 7이 있는지 확인하고 JRE 버전에 따라 적절한 래퍼 클래스를로드하십시오. 응용 프로그램이 특정 JRE, 타사 라이브러리 또는 응용 프로그램 등에 종속되지 않도록하기 때문에 일반적으로 좋은 디자인입니다.

두 번째 가능성은 서버에서 content-length 헤더 필드를 알 수 없으므로 getContentLength() 또는 getContentLengthLong() 메서드는 -1 값을 반환합니다.이것이 아마도 가장 빠른 수정이 될 것이기 때문에 다른 어떤 것보다 먼저 getContentLengthLong()을 시도하는 것이 좋습니다. 두 방법 모두 -1을 반환하면 [Apache JMeter] [11]과 같은 응용 프로그램을 사용하여 헤더 정보를 확인하는 것이 좋습니다. 이를 수행하는 빠른 방법은 JMeter가 "HTTP Proxy Server"브라우저의 프록시 설정을 실행하여 localhost를 주소로 사용하도록 설정하고 포트에 HTTP 프록시 서버를 설정 한 포트를 사용하게하는 것입니다. 기록 된 정보는 개별 요소로 표시되며 확장하면 각 헤더의 이름이 옆에있는 HTTP 헤더 관리자가 있어야합니다.

마지막으로 서버 자체에 대한 분석을 수행하여 문제가 있는지 확인할 수 있습니다. 로그가 정상적으로 보이고, 올바른 프로세스가 모두 실행되고, 구성이 올바르게 설정되고, 파일이 여전히 존재하고 올바른 위치에 있는지 확인하십시오. 서버가 콘텐츠 길이 요청에 더 이상 응답하지 않을 수 있습니다. 또한 코드가 다른 호스트의 JRE 7에서 작동하는지 확인하십시오.

이 제안 사항은 귀하에게 유용 할 것이며 귀하가 갖고있는 것으로 보이는이 문제를 해결할 수 있기를 바랍니다. 나는 또한 래퍼 클래스를 사용하고 미래에 사용할 제 3 자 클래스의 각 버전에 대한 노트를 따르도록 고려해야한다는 점을 유의할 필요가있다. 그래서 당신이 가지고있는 외부 의존성의 양을 줄이는 것과 같이 유지하기가 더 쉬운 더 나은 방법을 따르도록한다. 래퍼 클래스를 사용하여.

+0

감사합니다. 그러나, 자바 7 자바 의사는이 질문에 무관하다. 이 프로그램은 java 6을 기반으로 작성되었습니다. jre 6에서 정상적으로 작동합니다. jre 7에서는 ... uc.getContentLength()는 -1을 반환합니다. getContentLengthLong()은 Java 7에만 존재합니다. ftp 파일은 매우 작습니다. – lochi

+1

Javadoc은 코드 작성자와 Javadoc 주석이 정보가 코드 (예 : URLConnection)를 사용하는 프로그래머에게 필요할만큼 중요하다는 결론을 내 렸기 때문에 Javadoc은 관련이 없다고 결코 말할 수 없습니다. 많은 프로그래머가 할 일은 래퍼 클래스를 생성하여 래퍼가 업데이트되는 한 변경 사항이 변경 사항에 영향을받지 않도록합니다. 이 경우 동일한 메소드를 가진 랩퍼가 있지만 하나는 Java 6 용이고 다른 하나는 Java 7 용이고 어떤 것을 사용할 것인지 판별하려면 JRE 버전에 대한 빠른 점검을 수행하십시오. –

+0

안녕하세요, Matt, 의견 주셔서 감사합니다. 이 문제는 Sun이 1.3에서 1.4로 jre를 업그레이드했을 때 발생했습니다. 파일의 내용 길이가 여전히 미스터리 인 이유는 jre 1.7이 -1을 반환하는 이유입니다. 임시 수정으로 다운로드 진행률 표시 줄을 불확실한 진행률 표시 줄로 바꾸기로 결정했습니다. – lochi