【问题标题】:HttpClient:HttpGet Method failed: HTTP/1.0 503 Service UnavailableHttpClient:HttpGet 方法失败:HTTP/1.0 503 服务不可用
【发布时间】:2012-02-29 14:49:54
【问题描述】:

感谢阅读。

这样一个烦人的问题发生在我身上,我值得有人帮助我。 我在java中使用httpcomponent(以前的httpclient的新版本)来打开一些url和scrap内容。并且使用multihtread来提高性能。

这就是问题所在:

1.threads共享一个HttpClient

1)定义

private static final ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager();
private static HttpHost proxy = new HttpHost("127.0.0.1",8086,"http");
private static DefaultHttpClient http = new DefaultHttpClient(cm);

2) 在我的初始功能中

cm.setMaxTotal(100);
http.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

3)然后是我的线程函数

public static String getUrl(String url, String Chareset)
    {
        HttpGet get = new HttpGet(url);//uri
        get.setHeader("Content-Type", "text/html");
        get.setHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.50215;)");
        get.setHeader("Accept-Charset", Chareset+";q=0.7,*;q=0.7");//"utf-8;q=0.7,*;q=0.7");
    get.getParams().setParameter("http.socket.timeout",new Integer(CONNECTION_TIMEOUT));//20000

        String result = "";
        try {
            HttpResponse response = http.execute(get);
        if (response.getStatusLine().getStatusCode() != 200){//statusCode != HttpStatus.SC_OK) {
                System.err.println("HttpGet Method failed: "
                        + response.getStatusLine());//httpGet.getStatusLine()
        }
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            result = EntityUtils.toString(entity);
            EntityUtils.consume(entity);
            entity = null;
        }
    } catch(java.net.SocketException ee)
    {
            ee.printStackTrace();
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ee);
    }
        catch (IOException e) {
            //throw new Exception(e);
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, e);//TODO Debug
    } finally {
        get.abort();//releaseConnection();//TODO http.getConnectionManager().shutdown();?
        get = null;
    }
        return result; 
    }

4) 然后我创建了 10 个线程来调用 getUrl() 函数,但是在大约 1000 次循环之后,事情发生了:

**HttpGet Method failed: HTTP/1.0 503 Service Unavailable**

但是我用IE和代理打开了url,打开成功了。所以我的代理没有问题。

那怎么了?

2.然后我把httpclient的创建改成getUrl()函数,这样线程就不会共享HttpClient了,像这样:

public static String getUrl(String url, String Chareset)
    {
        HttpGet get = new HttpGet(url);//uri
        get.setHeader("Content-Type", "text/html");
        get.setHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.50215;)");
        get.setHeader("Accept-Charset", Chareset+";q=0.7,*;q=0.7");//"utf-8;q=0.7,*;q=0.7");
    get.getParams().setParameter("http.socket.timeout",new Integer(CONNECTION_TIMEOUT));//20000

        DefaultHttpClient http = new DefaultHttpClient(cm);//threads dont't share it
        http.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

        String result = "";
        try {
            HttpResponse response = http.execute(get);
        if (response.getStatusLine().getStatusCode() != 200){//statusCode != HttpStatus.SC_OK) {
                System.err.println("HttpGet Method failed: "
                        + response.getStatusLine());//httpGet.getStatusLine()
        }
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            result = EntityUtils.toString(entity);
            EntityUtils.consume(entity);
            entity = null;
        }
    } catch(java.net.SocketException ee)
    {
            ee.printStackTrace();
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ee);
    }
        catch (IOException e) {
            //throw new Exception(e);
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, e);//TODO Debug
    } finally {
        get.abort();//releaseConnection();//TODO http.getConnectionManager().shutdown();?
        get = null;
                http = null;//clean almost all the resources
    }
        return result; 
    }

然后在 10 个线程的大约 600 次循环之后,又发生了另一件事:

**Exception in thread "Thread-11" java.lang.OutOfMemoryError: Java heap space**

result = EntityUtils.toString(entity); 行发生异常

所以,真的需要一些帮助。

谢谢!

【问题讨论】:

  • 原来是我被拒绝了。为了不被拒绝,我不得不使用第二种方式:在每个线程的每个循环中新建一个httpclient。还有Java gc()太慢了,所以我认为 sleep() 可能是个好主意,或者我可以用标志重置 prog 以指示进度。谢谢所有答案!
  • 我终于想通了。这种方法有效。而其他地方有内存泄漏。对不起...

标签: java multithreading httpclient out-of-memory apache-httpcomponents


【解决方案1】:

503 表示服务不可用,因此服务已关闭。现在,这可能是由于您实际上一遍又一遍地访问同一个服务并最终出现错误或由于此类负载而拒绝您的服务。

第二个错误很清楚:没有更多的内存,因为你已经用完了。您的程序正在泄漏内存,或者您应该使用 -Xmx256m、-Xmx512m、-Xmx1G 等来增加堆大小......对于这些问题,有很多关于 SO 的答案。

【讨论】:

  • 首先我可以在程序运行的同时通过IE和同一个代理打开url,所以为什么它不拒绝我!第二个问题,我知道它没有更多内存了,因为我全部使用了。我只是不知道为什么。getUrl() 函数几乎是所有代码。所以告诉我我的程序在哪里泄漏内存而不是谈论某事我已经知道了,好吗?
  • 不同的客户端会导致不同的响应。不是因为 IE 工作,HTTPClient 应该工作。不同的会话、不同的代理等等……你绝对不应该依赖 IE 来判断它是否有效。此外,可能因为 1000 个请求而导致另一端的服务中断,但其中几个可能没有问题
  • 你看到 User-Agent 字段了吗?那是我 PC 上的 firefox。我把它伪装成 firefox,使用 firefox 打开 url 也可以!
  • 用户代理不会让你伪造浏览器。例如,您绝对没有重复使用浏览器 cookie,或者您没有共享同一个会话。另外,正如我所说,服务器可能有几个请求是可以的,但可能不是 1000 个。
  • 我试过firefox和IE在这个程序运行时打开相同的url。所以我认为它没有拒绝我。
【解决方案2】:

纪尧姆给出的答案在我看来完全合理。就第二个问题而言,OutOfMemoryError 的原因很简单。 DefaultHttpClient 对象非常昂贵,并且通过为每个请求创建一个新实例,您会更快地耗尽系统资源。此外,除了简单的测试之外,通常应避免使用EntityUtils#toString。应该将 HTTP 响应消息作为内容流使用,而无需在内存中缓冲整个响应正文。

【讨论】:

  • 应该将 HTTP 响应消息作为内容流使用,而不会将整个响应正文缓冲在内存中。那我该怎么办?entity.getContent?谢谢。
  • 我怀疑这个答案。所有的网址都是不同的,它们有很多。每个线程都会打开一个不同的 url。如果 url a 拒绝我,为什么 url b 也拒绝我?并且我使用IE和Firefox同时使用同一个代理打开其中一个url,并且成功。所以我认为这个逻辑是非常正确的。在我打开一个网址后,我可能应该做些什么来清理资源。
  • @Rusty:是的,你应该使用 HttpEntity#getContent 返回的 InputStream 并且只读取足够的数据来完成工作。
  • @Rusty:我怀疑如果您打开 10 个 IE 实例并编写脚本以在紧密循环中执行 1000 个请求,您也会开始看到 503。我仔细检查了您的代码 sn-p (1) 并没有发现任何资源释放问题。
  • :谢谢,伙计。我终于弄清楚了。我被拒绝了。为了不被拒绝,我必须使用第二种方式:在每个线程的每个循环中新建一个 httpclient。并且Java gc() 太慢了,所以我认为 sleep 可能是个好主意,或者我可以用标志重置 prog 以指示进度。无论如何谢谢
猜你喜欢
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 2021-06-16
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多