【问题标题】:Download a file via a proxy java通过代理 java 下载文件
【发布时间】:2016-03-22 14:54:19
【问题描述】:

我通过代理从www.example.com/example.pdf 之类的网址下载文件并将其保存在java 中的文件系统上时遇到问题。有人对这如何工作有想法吗?如果我得到 InputStream,我可以简单地将其保存到文件系统:

final ReadableByteChannel rbc = Channels.newChannel(httpUrlConnetion.getInputStream());    
final FileOutputStream fos = new FileOutputStream(file);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();

但是如何通过代理获取 url 的输入流? 如果我这样做:

SocketAddress addr = new InetSocketAddress("my.proxy.com", 8080);
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
URL url = new URL("http://my.real.url.com/");
URLConnection conn = url.openConnection(proxy);

我遇到了这个异常:

java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at java.io.BufferedInputStream.fill(Unknown Source)
    at java.io.BufferedInputStream.read1(Unknown Source)
    at java.io.BufferedInputStream.read(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
    at app.model.mail.crawler.newimpl.FileLoader.getSourceOfSiteViaProxy(FileLoader.java:167)
    at app.model.mail.crawler.newimpl.FileLoader.process(FileLoader.java:220)
    at app.model.mail.crawler.newimpl.FileLoader.run(FileLoader.java:57)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

使用这个:

final HttpURLConnection httpUrlConnetion = (HttpURLConnection) website.openConnection(proxy);
httpUrlConnetion.setDoOutput(true);
httpUrlConnetion.setDoInput(true);
httpUrlConnetion.setRequestProperty("Content-type", "text/xml");
httpUrlConnetion.setRequestProperty("Accept", "text/xml, application/xml");
httpUrlConnetion.setRequestMethod("POST");
httpUrlConnetion.connect();

我可以下载一个网站的源代码,它是 html,但不是文件,也许有人可以帮助我设置下载文件的属性。

【问题讨论】:

  • 如果您只需要设置代理设置,请参阅 Oracle 的 this document,或者如果您想切入正题,请参阅 this old StackOverflow question
  • 系统属性不起作用,因为我想在执行下载的每个线程中使用不同的代理。所以我必须为每个连接设置代理
  • 上面的 Oracle 文档指定了如何执行此操作。我添加了一些示例代码的答案。
  • 对我不起作用它给了我一个例外
  • 可能不是代理的问题。有关此错误的原因列表,请参阅 stackoverflow.com/questions/585599/…。我的猜测是超时,并检查是否尝试下载一个非常小的文件。

标签: java http proxy stream connection


【解决方案1】:

以下内容与其他答案不同,对我有用:在连接之前设置这些属性:

            System.getProperties().put("http.proxySet", "true");
            System.getProperties().put("http.proxyHost", "my.proxy.com");
            System.getProperties().put("http.proxyPort", "8080"); //port is String, not int

然后,打开 URLConnection 并尝试下载文件。

【讨论】:

  • 我在不同的线程中使用不同的代理,所以这不起作用
【解决方案2】:

可以使用 Apache httpclient 库来解决代理的大部分问题。编译下面的代码,可以使用下面的maven:

马文:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>stackoverflow.test</groupId>
  <artifactId>proxyhttp</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>proxy</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.1</version>
    </dependency>
  </dependencies>
</project>

Java 代码:

import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

/**
 * How to send a request via proxy.
 *
 * @since 4.0
 */
public class ClientExecuteProxy {

    public static void main(String[] args)throws Exception {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            HttpHost target = new HttpHost("www.google.com", 80, "http");
            HttpHost proxy = new HttpHost("127.0.0.1", 8889, "http");

            RequestConfig config = RequestConfig.custom()
                    .setProxy(proxy)
                    .build();
            HttpGet request = new HttpGet("/");
            request.setConfig(config);

            System.out.println("Executing request " + request.getRequestLine() + " to " + target + " via " + proxy);

            CloseableHttpResponse response = httpclient.execute(target, request);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                System.out.println(EntityUtils.toString(response.getEntity()));
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}

【讨论】:

  • 我收到 HTTP 响应代码:411、读取超时或连接超时……有什么想法吗?
  • @Exagon 我已经更新了代码,因为上次我使用了我为旧版本编写的代码,该代码使用了所有已弃用的类。我使用 fiddler2 作为代理重新测试了代码。它工作得很好。如果超时,则可能是“网络”问题。
  • 顺便说一下,这个例子只是一个“复制和粘贴”的:hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/…
  • 对不起,我在 request.setConfig(config); “HttpGet 类型的方法 setConfig(RequestConfig) 未定义”
  • @exagon 您使用的是什么版本的库?如果不想使用maven,可以从以下地址下载我使用的版本:central.maven.org/maven2/org/apache/httpcomponents/httpclient/…
【解决方案3】:

以编程方式设置代理:

SocketAddress addr = new InetSocketAddress("my.proxy.com", 8080);
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
URL url = new URL("http://my.real.url.com/");
URLConnection conn = url.openConnection(proxy);

然后您可以将上面的代码与最后一行返回的URLConnection 一起使用。如果您愿意,也可以使用 SOCKS 代理,或强制不使用代理。

这是从this Oracle documentation 拍摄的(并略有编辑)。

【讨论】:

  • 如果我这样做,我会遇到异常,再次查看我的问题,我将对其进行编辑
  • 不幸的是,在您的情况下,很难说出为什么会重置连接。您是否尝试过在浏览器中使用相同的代理设置访问 URL,并确保它在那里工作?您是否使用了正确的代理类型(SOCKS 与 HTTP)?
  • 我正在使用 SOCKS 是的,我做到了,而且效果很好……我现在在很多其他网站上尝试过,但从来没有用过
  • 你把代码中的Proxy.Type.HTTP改成Proxy.Type.SOCKS了吗?以防万一,您可以同时尝试。
  • 嗯,我不确定。我假设您已经在代码中验证了您的代理主机和端口。除此之外,我不确定该建议什么。 :(
【解决方案4】:

另一种方法是在 httpUrlConnection 的每个实例“内部”实现代理。那就是:

  1. 不要连接到您想要的真实 URL。首先,连接到代理 IP 和端口,但使用 http GET 方法引用您想要的 URL。
  2. 使用 setRequestPropertyhost 设置为您的 URL 和您可能需要的任何其他标头。

如果有效,连接会透明地将文件发送给您。

我有一些代码可以使用 Sockets。

try {
    Socket sock = new Socket("10.0.241.1", 3128); //proxy IP and port
    InputStream is = sock.getInputStream();
    OutputStream os = sock.getOutputStream();
    String str = "GET http://www.uol.com.br HTTP/1.1\r\n"; //GET your site
    str += "Host: www.uol.com.br\r\n"; //again, Host of your site
    str += "Proxy-Authorization: Basic ZWR1YXJkby5wb2NvOmM1NmQyMw==\r\n"; //if password is needed
    str += "\r\n";
    os.write(str.getBytes());
    byte[] bb = new byte[1024];
    int L = 0;
    while ((L = is.read(bb)) != -1) {
        //write bytes to file stream...
    }
} catch (Exception ex) {
    //exception handling...
}

“当一个人可以使用 httpUrlConnection 时,为什么有人会使用纯套接字?”,你说。嗯,那个时候,我还不知道httpUrlConnection。

【讨论】:

  • 你能用一些代码展示如何对所有属性执行此操作吗?
  • 已在答案中编辑。这个实现是从我不知道httpUrlConnection的时候开始的,所以使用了sockets。匆忙进行了编辑,我想您可以在 httpUrlConnection 上找出等效的操作。如果您需要,我会再次对其进行编辑以适合 httpUrlConnection。
猜你喜欢
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 2012-06-02
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
  • 2016-07-19
  • 2016-01-18
相关资源
最近更新 更多