【发布时间】: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编码后将它们连接起来。你觉得这个主题还有什么可做的吗?
标签: java android http httpurlconnection httpsurlconnection