Android 的 HTTP CONNECT 方法
HTTP CONNECT method with Android
我想扩展现有的 Android 应用程序,该应用程序建立到远程设备的 http 连接,它向远程设备发送命令并从中接收值。
该功能包括通过已设置的自定义代理服务器的隧道连接。我有给定的 http header 格式,它应该使代理服务器为我的应用程序创建并提供隧道。
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。
我现在想知道是否有任何预期的方法可以使用 Apache HttpClient 来实现它,以及使用给定的示例数据会是什么样子,或者我是否必须为此实现自己的方法。如果是这样,它应该实现哪个接口(有一些接口听起来很适合继承)。
如有任何解释、摘要或指示,我们将不胜感激。
更新:
我现在设置了一个小片段,没有 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.
}
在 "it could actually work" 方面,这对我来说相当不错。
无论如何,我收到以下日志和跟踪:
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 org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@bc6a08
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)
知道哪里出了问题吗?
更新:如前所述here,这可能是由于重定向时的错误。目标确实重定向的事实告诉我,我没有到达正确的目标,这意味着 Host
参数可能没有被覆盖。
事实上,HttpClient
根本无法做到这一点,我试错了级别。当使用 TcpSocket
(或 SSLSocket
)时它会起作用。自定义的CONNECT
header可以这样简单的拼装发送:
final Socket tcpSocket = SSLSocketFactory.getDefault().createSocket("host ip", 443);
String connect = "custom CONNECT header";
tcpSocket.getOutputStream().write((connect).getBytes());
tcpSocket.getOutputStream().flush();
然后可以使用 BufferedReader
或其他任何方式读取来自服务器的响应。
我想扩展现有的 Android 应用程序,该应用程序建立到远程设备的 http 连接,它向远程设备发送命令并从中接收值。
该功能包括通过已设置的自定义代理服务器的隧道连接。我有给定的 http header 格式,它应该使代理服务器为我的应用程序创建并提供隧道。
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。
我现在想知道是否有任何预期的方法可以使用 Apache HttpClient 来实现它,以及使用给定的示例数据会是什么样子,或者我是否必须为此实现自己的方法。如果是这样,它应该实现哪个接口(有一些接口听起来很适合继承)。
如有任何解释、摘要或指示,我们将不胜感激。
更新:
我现在设置了一个小片段,没有 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.
}
在 "it could actually work" 方面,这对我来说相当不错。 无论如何,我收到以下日志和跟踪:
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 org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@bc6a08
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)
知道哪里出了问题吗?
更新:如前所述here,这可能是由于重定向时的错误。目标确实重定向的事实告诉我,我没有到达正确的目标,这意味着 Host
参数可能没有被覆盖。
事实上,HttpClient
根本无法做到这一点,我试错了级别。当使用 TcpSocket
(或 SSLSocket
)时它会起作用。自定义的CONNECT
header可以这样简单的拼装发送:
final Socket tcpSocket = SSLSocketFactory.getDefault().createSocket("host ip", 443);
String connect = "custom CONNECT header";
tcpSocket.getOutputStream().write((connect).getBytes());
tcpSocket.getOutputStream().flush();
然后可以使用 BufferedReader
或其他任何方式读取来自服务器的响应。