2015-03-02 302 views
1

我想扩展一个现有的Android应用程序,该应用程序建立一个http连接到一个远程设备,它将命令发送到并从中接收值。与Android连接的HTTP CONNECT方法

该功能由通过已设置的自定义代理服务器的隧道连接组成。我给了http头格式,它应该使代理服务器创建并为我的应用程序提供隧道。

CONNECT <some id>.<target ip>:80 HTTP/1.1 
Host: <proxy ip>:443 
Authorization: basic <base64 encoded auth string> 

# Here beginns the payload for the target device. It could be whatever. 
GET/HTTP/1.1 
Host: 127.0.0.1:80

该应用程序使用Apache HttpClient库处理它的连接,我想与整合。然而,这不是强制性的。
授权标准符合基本认证。

我遇到了麻烦,因为我不清楚HttpClient是如何用于这种行为的。 库中没有CONNECT方法,只有GET,POST等。我认为这将通过HttpClient实例的代理设置进行管理。
这里的问题是,请求行不是标准的,因为CONNECT行包含一个id,自定义代理将解析和解析该id。

我现在想知道是否有任何想用的方法来实现这个使用Apache HttpClient以及它给这个样本数据看起来像什么,或者如果我必须实现我自己的方法。如果是这样,哪个接口(有一些听起来合理的继承)应该实现。

任何解释,片段或指针,将不胜感激。

UPDATE: 我现在有一个小的片段,没有Android。只需简单的Java和Apache HttpClient。我仍然认为请求中的Host不匹配是个问题,因为我无法建立连接。

final HttpClient httpClient = new DefaultHttpClient(); 

// Set proxy 
HttpHost proxy = new HttpHost (deviceId + "." + "proxy ip", 443, "https"); 
httpClient.getParams().setParameter (ConnRoutePNames.DEFAULT_PROXY, proxy); 

final HttpGet httpGet = new HttpGet("http://" + "target device ip"); 
httpGet.addHeader ("Authorization", "Basic" + 
    Base64.encodeBase64String((username + ":" + password).getBytes())); 
// Trying to overvrite the host in the header containing the device Id 
httpGet.setHeader("Host", "proxy ip"); 

System.out.println("Sending request.."); 
try { 
    final HttpResponse httpResponse = httpClient.execute (httpGet); 
    final InputStream inputStream = httpResponse.getEntity().getContent(); 
    final InputStreamReader inputStreamReader = 
     new InputStreamReader(inputStream, "ISO-8859-1"); 

    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 

    final StringBuilder stringBuilder = new StringBuilder(); 
    String bufferedStrChunk = null; 

    while ((bufferedStrChunk = bufferedReader.readLine()) != null) { 
     stringBuilder.append (bufferedStrChunk); 
    } 

    System.out.println("Received String: " + stringBuilder.toString()); 
} 
catch (final ClientProtocolException exception) { 
    System.out.println("ClientProtocolException"); 
    exception.printStackTrace(); 
} 
catch (final IOException exception) { 
    System.out.println("IOException"); 
    exception. 
} 

这对我来说看起来相当不错,“它可以实际工作”的方式。 不管怎么说,我收到下面的日志和跟踪:

Sending request.. 
2015/03/03 13:16:16:199 CET [DEBUG] ClientParamsStack - 'http.route.default-proxy': https://"device id"."proxy ip":443 
2015/03/03 13:16:16:207 CET [DEBUG] SingleClientConnManager - Get connection for route HttpRoute[{}->https://"device id"."proxy ip":443->http://"target device ip"] 
2015/03/03 13:16:16:549 CET [DEBUG] ClientParamsStack - 'http.tcp.nodelay': true 
2015/03/03 13:16:16:549 CET [DEBUG] ClientParamsStack - 'http.socket.buffer-size': 8192 
2015/03/03 13:16:16:563 CET [DEBUG] DefaultClientConnection - Connection shut down 
2015/03/03 13:16:16:563 CET [DEBUG] SingleClientConnManager - Releasing connection [email protected]6a08 
Exception in thread "main" java.lang.IllegalStateException: Unable to establish route. 
planned = HttpRoute[{}->https://"device id"."proxy ip":443->http://"target device ip"] 
current = HttpRoute[{s}->https://"device id"."proxy ip":443->http://"target device ip"] 
    at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:672) 
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:385) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554) 
    at run.main(run.java:71) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

任何想法什么不顺心?

UPDATE:正如here所述,这可能是由于重定向时的错误。目标确实重定向的事实告诉我,我没有达到正确的目标,这意味着Host参数可能没有被覆盖。

回答

0

事实上,这根本不能用HttpClient完成,我尝试了错误的等级。它适用于完成TcpSocket(或SSLSocket)。自定义首部CONNECT可以简单地进行组装和像发送:

final Socket tcpSocket = SSLSocketFactory.getDefault().createSocket("host ip", 443); 
String connect = "custom CONNECT header"; 

tcpSocket.getOutputStream().write((connect).getBytes()); 
tcpSocket.getOutputStream().flush(); 

来自服务器的响应然后可以用一个BufferedReader或任何读取。

+0

hi @mgr。我也面临这样的情况。你能详细解释一下吗?是否如此简单,您可以在通过上述几行代码建立隧道连接之后,通过HttpClient/HttpUrlConnetion运行您的普通Http请求?和setProxy的请求? – tainy 2015-12-16 03:00:06

+0

我没有找到一种方法来使用我刚刚用HttpClient打开的套接字,并使用套接字手动执行了这些操作(可能缺少一些错误处理和完整性检查)。我为此项目手动接收并分割了inputStream上的响应。 对不起,我不能提供任何建议,但这不是我每天都做的。 – mgr 2016-01-08 09:55:44