2015-03-02 57 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