【问题标题】:HttpsUrlConnection Android vs Native JavaHttpsUrlConnection Android vs Native Java
【发布时间】:2016-11-05 07:57:07
【问题描述】:

我编写了一些代码,试图“作为浏览器”与网站进行通信(在 cookie 和标头方面)。我目前有四个请求(GET、POST、POST、GET)。

代码非常简单:打开连接、添加标头和 cookie、解析响应。

获取代码:

conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setUseCaches(false);
conn.setRequestProperty("User-Agent", userAgent);
conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
conn.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
if (cookies != null) {
    for (String cookie : this.cookies) {
        conn.addRequestProperty("Cookie", cookie.split(";", 1)[0]);
    }
}
int responseCode = conn.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();

while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();

setCookies(conn.getHeaderFields().get("Set-Cookie"));

return response.toString();

邮政编码:

conn = (HttpsURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Host", "...");
conn.setRequestProperty("User-Agent", userAgent);
conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
conn.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
conn.setRequestProperty("Accept-Encoding","identity");
for (String cookie : this.cookies) {
    conn.addRequestProperty("Cookie", cookie.split(";", 1)[0]);
}
conn.setRequestProperty("Connection", "keep-alive");
conn.setRequestProperty("Referer", "https://...");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", Integer.toString(postParams.length()));

conn.setDoOutput(true);
conn.setDoInput(true);

DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(postParams);
wr.flush();
wr.close();

int responseCode = conn.getResponseCode();
InputStream is = responseCode != 400 ? conn.getInputStream() : conn.getErrorStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String inputLine;
StringBuilder response = new StringBuilder();

while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();

return response.toString();

该程序在我的电脑上运行良好。但是,在 Android 设备上运行它时,第二次 POST 遇到了多个问题;在一台设备上出现Too many redirections 异常,而在另一台设备上(我关注的那个)我只是收到400 Bad Request,尽管完全相同的请求在我的PC 上返回200。

我注意到实际上有两种不同的实现:在 PC 上我使用 sun.net.www.protocol.https.DelegateHttpsURLConnection,在 Android 上它是 com.android.okhttp.internal.http.HttpURLConnectionImpl。对象conn 在运行时看起来有点不同。但是,我没有找到有意义的区别(如果需要,我可以发布这些对象的全部内容);我发现在第一个 GET 中设置的 cookie 存在一个差异,但手动操作导致相同的 400。

我尝试使用 Wireshark 捕获 Android 输出请求,但结果是加密的,我无法解密。

我基本上想到了两种可能的情况:

  • 找出这些实现之间的差异并采取相应措施。
  • 找到一种在 Android 上使用 sun.net.www.protocol.https.DelegateHttpsURLConnection 的方法。

到目前为止,我还没有弄清楚其中的任何一个。这些实现是否有任何已知的差异/问题?有没有办法在 Android 上运行本机 Java 库?任何帮助将不胜感激,谢谢。

【问题讨论】:

  • 记录或验证没有标题被欺骗或存在额外的标题。 stackoverflow.com/questions/22173517/… 并尝试使用 'writer' 对正文中的原始字节进行编码。最后一点就像将字节数组转换为流。
  • 在获取输出流之前记录标头会导致异常,因为它在请求标头时隐式获取流。在“手表”窗口中查看类似内容时,我也遇到了同样的情况。
  • 关于您的第二条建议,我目前仅针对 POST 请求的输入参数执行此操作(请参阅变量 postParams)。使用 JSoup,我将所有元素标记为 input,并在使用 URLEncoder.encode 编码后将它们连接起来。你觉得这个主题还有什么可做的吗?
  • 在这里尝试审查“帖子”:tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection

标签: java android http httpurlconnection httpsurlconnection


【解决方案1】:

是的,这些 SDK 之间存在一些差异,桌面版是 Oracle sdk,而 Android 版是 Google 发布的。

无论如何,在 Android 上执行 http 请求时,建议使用 RetrofitVolley

【讨论】:

  • 我在过去几天专注于 Volley,到目前为止,我遇到并没有设法在同一阶段解决问题,我担心它实际上依赖于 HttpUrlConnection 所以它是几乎是一个死胡同......
  • 您知道是否可以使用 Oracle SDK?我读到了可以使用 C 和 C++ 的 NDK,也许原生 Java 也有类似的东西。
  • 不,您不能使用 Oracle SDK
猜你喜欢
  • 1970-01-01
  • 2011-10-02
  • 2013-03-02
  • 2017-06-18
  • 2014-06-11
  • 2017-04-24
  • 2011-03-03
  • 1970-01-01
  • 2013-11-12
相关资源
最近更新 更多