关于新浪微博SDK在代理服务网络环境中遇到的问题 weibo4j.model.MySSLSocketFactory.createSocket

最近客户在使用我们的新浪微博应用的时候突然不能使用了,后台抛出的异常如下:

Caused by: java.net.SocketTimeoutException: connect timed out
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:525)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:550)
at weibo4j.model.MySSLSocketFactory.createSocket(MySSLSocketFactory.java:88)
at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:706)
at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1321)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:386)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396)
atorg.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
at weibo4j.http.HttpClient.httpRequest(HttpClient.java:397)

经过跟客户沟通发现,他们的环境配置了Apache反向代理,但是公司内部也配置了Apache反向代理,微博应用可以正常使用,因此排除反向代理的问题;进一步沟通发现,客户的网络环境配置的代理服务器,且新浪、网易、腾讯平台的微博应用均不能正常使用了。

开始以为是微博平台的SDK不支持代理服务器,但是查看SourceCode发现,在新浪的weibo4j.model.Configuration类中,有几行注释的代码:
 //defaultProperty.setProperty("weibo4j.https.proxyHost","");
        //defaultProperty.setProperty("weibo4j.https.proxyUser","");
        //defaultProperty.setProperty("weibo4j.https.proxyPassword","");
        //defaultProperty.setProperty("weibo4j.https.proxyPort","");
 
推测SDK是支持代理服务器的。而且在weibo4j.http.HttpClient的构造方法中,存在
// 支持proxy
        if (proxyHost != null && !proxyHost.equals("")) {
…………
}
的判断。
 
 
因此将Configuration中代理的注释去掉,并把属性配置上参数值,重新访问仍然报异常!
然后跟踪代码发现weibo4j.http.HttpClient.httpRequest(HttpClient.java:397)地方,新浪的实现为:
client.executeMethod(method);
追踪Apache Commons-HttpClient的源代码发现:
public int executeMethod(HttpMethod method)
        throws IOException, HttpException  {
            
        LOG.trace("enter HttpClient.executeMethod(HttpMethod)");
        // execute this method and use its host configuration, if it has one
        return executeMethod(null, method, null);
    }
public int executeMethod(final HostConfiguration hostConfiguration, final HttpMethod method)
        throws IOException, HttpException {
    
        LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod)");
 
        return executeMethod(hostConfiguration, method, null); 
    }

但是新浪使用client.executeMethod(method),而代理是在HostConfiguration的ProxyHost中设置的,这里把代理信息给丢掉了!!!

因此需要修改为:
if(getProxyHost() != null && getProxyHost().length() > 0){
   log.debug("HOSTCONFIGURATION: " + client.getHostConfiguration().toString());
   client.executeMethod(client.getHostConfiguration(), method);
}else{
   client.executeMethod(method);
}

重新部署应用后再次访问仍然报异常!疯了!!!

追踪了半天Apache Commons-HttpClient的源代码,在要撞南墙的时候终于发现问题:
 
新浪SDK OAuth2.0版本采用的是HTTPS协议,并且在weibo4j.http.HttpClient的构造方法中注册了HTTPS的SSLSocketFactory
 Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);
        Protocol.registerProtocol("https", myhttps);
但是在代理服务器注册的部分,采用的方法为:
client.getHostConfiguration().setProxy(proxyHost, proxyPort);

亲,追踪了半天Apache Commons-HttpClient的源代码才发现,setProxy注册的是HTTP协议好么!!!org.apache.commons.httpclient.HostConfiguration中
   
    public synchronized void setProxy(final String proxyHost, int proxyPort) {
        this.proxyHost = new ProxyHost(proxyHost, proxyPort); 
    }

而ProxyHost是这样构造的:
    public ProxyHost(final String hostname, int port) {
        super(hostname, port, Protocol.getProtocol("http"));
    }
是HTTP好么!!!怎么拿HTTP和HTTPS去通信呢。。。。让一点都不懂HttpClient的我搞得做梦都是异常堆栈里的调用关系啊!新浪你坑爹啊!

最后,把这个修改为:
//使用默认的setProxy端口,注册的为ProxyHost,此方式注册的为HTTP协议,无法与HTTPS协议通信,将会报错
//新浪OAuth协议采用HTTPS协议,代理请求也必须为HTTPS协议
            final String proxyHostName = proxyHost;
            final HttpHost proxyHost = new HttpHost(proxyHostName, proxyPort, new Protocol("https", new MySSLSocketFactory(), proxyPort));

OK了!接着搞腾讯和网易去!根据经验,腾讯的SDK更坑爹啊!!!泪奔ING。。。

你可能感兴趣的:(sina,weibo)