Java 7 URL连接失败

4
下面的代码在Java 6(以及更早版本)下工作正常,但在更新到JRE 7(Java 7)后停止工作。
URL是FTP文件:

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

这是我得到的输出:

application/octet-stream -1 [Ljava.lang.StackTraceElement; @ 5419f97c

这是我的代码:
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:
Area: API: Networking
Synopsis: Server Connection Shuts Down when Attempting to Read Data When http Response Code is -1

如何使这段代码与Java 7兼容?

描述:由于修复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方法。 不兼容性质:行为 请求增强功能(RFE):7055058
问题显然出现在getContentLength()方法上。 使用JRE6时,此方法返回一个值,但使用JRE7时,我得到了-1。

1
也许值得检查服务器返回的内容长度,例如通过使用Wireshark嗅探网络。此外,您确定相同的代码仍适用于Java 6吗?即您是否已排除更改为Java 7并停止工作的可能性是巧合的可能性? - DNA
它可以与Java 6一起使用,这不是巧合。我对此100%确定。请查看添加的内容。在这种情况下,URL是FTP而不是HTTP。 - lochi
1个回答

2
根据Java 7的JavadocURLConnection,这种情况有两个可能的原因。
可能的第一个原因是内容长度大于Integer.MAX_VALUE。要确定是否存在此问题,我会使用getContentLengthLong(),因为它返回长整型而不是整型,如果内容长度大于Integer.MAX_VALUE,getContentLength()将返回-1。另外,自Java 7以来,建议使用getContentLengthLong()而不是getContentLength(),如Java 7的URLConnection Javadoc所述,“它返回一个长整型,因此更加可移植”。如果您想同时使用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",并将浏览器的代理设置为使用本地主机作为地址,HTTP代理服务器的端口作为端口。记录的信息将显示为单独的元素本身,如果您展开它们,应该会有一个HTTP Header Manager,其中包含每个Header的名称及其旁边的值。
最后,您可能想要对服务器本身进行分析,以查看是否存在任何问题。验证日志是否正常,所有正确的进程是否启动,配置是否设置正确,文件是否仍然存在并位于正确位置等等。也许服务器不再设置为响应内容长度请求。此外,验证您的代码是否在另一台主机上使用JRE 7功能。
我希望这些建议对您有价值,并且您能够解决似乎遇到的这个问题。我还要指出,您真的应该考虑使用包装类,并遵循每个第三方类版本的注释,以便遵循更好的实践,这样更易于维护,例如通过使用包装类来减少外部依赖的数量。

谢谢。但是,Java 7的Java文档与此问题无关。该程序是基于Java 6编写的。在jre 6上运行良好。使用jre 7时会出现问题... uc.getContentLength()返回-1。getContentLengthLong()仅存在于Java 7中。FTP文件非常小。 - lochi
1
我永远不会说Javadoc是无关紧要的,因为编写代码和Javadoc注释的人确定了这些信息对使用他们的代码的程序员非常重要(例如URLConnection)。许多程序员会创建包装类,以便如果有更改,只要更新了包装器,您的程序就不会受到影响。在这种情况下,您将拥有具有相同方法的包装器,但一个用于Java 6,另一个用于Java 7,并且要确定使用哪个,请快速检查JRE版本。 - Matt Pascoe
嗨,马特,感谢您的评论。当Sun将jre从1.3升级到1.4时,这个问题就存在了。为什么jre 1.7返回文件内容长度为-1仍然是一个谜。作为一个临时解决方案,我决定用不确定进度条替换下载进度条。 - lochi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接