在开发新浪微博的时候,遇到了“The target server failed to respond”这个错误。
通过遍地搜索,在GoogleIssue
Every time my application is started it takes upwards to a minute for HTTPS Post(via http proxy) to return results (
See code below). Once the first Post returns results, all following requests seem to return at a
reasonable speed. I reuse the androidHttpClient, and after about three minute passed, the next HTTPS Post request to server hangs long again.
The problem is not on the
server side since HTTPS Post to the server(via http proxy) in another platform(window mobile/s60/iphone) return results not hanging so long.
System:
Running on device vodafon, HTC Magic 2.1-update1.
Sample code that causes the problem:
static AndroidHttpClient androidHttpClient = null;
public String sendRequest(String strReqData, String strUrl, Context context)
{
String strResponse = null;
ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
pairs.add(new BasicNameValuePair("requestData", strReqData));
UrlEncodedFormEntity p_entity;
try
{
BaseHelper.log("dest url : ", strUrl);
URL url = new URL(strUrl);
long lstart = System.currentTimeMillis();
if( androidHttpClient == null )
androidHttpClient = AndroidHttpClient.newInstance("ua_alipay");
//
// proxy config.
HttpParams httpParams = androidHttpClient.getParams();
HttpHost proxy = getProxy(context);
httpParams.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
String protocol = url.getProtocol();
int port = 80;
if( protocol.equalsIgnoreCase("https") )
port = 443;
HttpHost target = new HttpHost(url.getHost(), port, protocol);
HttpPost httpost = new HttpPost(strUrl);
p_entity = new UrlEncodedFormEntity(pairs, "utf-8");
httpost.setEntity(p_entity);
HttpResponse response;
response = androidHttpClient.execute(target, httpost);
HttpEntity entity = response.getEntity();
String strRet = EntityUtils.toString(entity);
long lend = System.currentTimeMillis();
BaseHelper.log("start at: ", String.valueOf(lstart) + "(ms)");
BaseHelper.log("finished at: ", String.valueOf(lend) + "(ms)");
float lEalpse = (float)((lend - lstart)/1000.0);
String Ealpse = String.valueOf(lEalpse);
BaseHelper.log(" cost : ", Ealpse + "(s)");
strResponse = strRet;
strResponse += (" cost : " + Ealpse);
}
catch (Exception e)
{
e.printStackTrace();
strResponse = (e.toString() + "\n" + e.getLocalizedMessage() + "\n" + e.getCause());
}
finally
{
}
return strResponse;
}
public HttpHost getProxy(Context context)
{
HttpHost proxy = null;
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if(ni != null && ni.isAvailable() && ni.getType() == ConnectivityManager.TYPE_MOBILE)
{
String proxyHost = android.net.Proxy.getDefaultHost();
int port = android.net.Proxy.getDefaultPort();
if (proxyHost != null)
proxy = new HttpHost(proxyHost, port);
}
return proxy;
}
#14 [email protected]I'm fixing the problem in Ice Cream Sandwich.
For earlier releases, the following ugly hack will prevent Android's Apache HTTP client from forgetting the target's host name while it is connecting. That way when it later logs that host name, it won't waste time doing a reverse DNS lookup.
Call this method on your DefaultHttpClient or AndroidHttpClient instance. It will prevent the reverse DNS lookup from being made.
private void workAroundReverseDnsBugInHoneycombAndEarlier(HttpClient client) {
// Android had a bug where HTTPS made reverse DNS lookups (fixed in Ice Cream Sandwich)
// http://code.google.com/p/android/issues/detail?id=13117
SocketFactory socketFactory = new LayeredSocketFactory() {
SSLSocketFactory delegate = SSLSocketFactory.getSocketFactory();
@Override public Socket createSocket() throws IOException {
return delegate.createSocket();
}
@Override public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params) throws IOException {
return delegate.connectSocket(sock, host, port, localAddress, localPort, params);
}
@Override public boolean isSecure(Socket sock) throws IllegalArgumentException {
return delegate.isSecure(sock);
}
@Override public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException {
injectHostname(socket, host);
return delegate.createSocket(socket, host, port, autoClose);
}
private void injectHostname(Socket socket, String host) {
try {
Field field = InetAddress.class.getDeclaredField("hostName");
field.setAccessible(true);
field.set(socket.getInetAddress(), host);
} catch (Exception ignored) {
}
}
};
client.getConnectionManager().getSchemeRegistry()
.register(new Scheme("https", socketFactory, 443));
}
Another option is to consider HttpURLConnection. In Froyo and earlier, HttpURLConnection had some frustrating bugs. Most notably, calling close() on a response InputStream without reading all of its data didn't prevent the connection from being pooled. Froyo also lacked support for cookies. HttpURLConnection is the best Android HTTP client for Gingerbread and better. It's workable on Eclair and Froyo. This is where the Dalvik team is spending its effort going forward.