使用HttpURLConnection发起POST请求遇"过时浏览器"提示问题求助
问题背景
我在用Java的HttpURLConnection开发应用时碰到了个头疼的问题:
- 先向目标站点发送POST请求获取token,这一步一切正常
- 拿着拿到的token向同一站点的另一个接口发起第二次POST请求,虽然返回状态码是200,但响应内容却提示"您正在使用过时浏览器,请更新浏览器"
- 已经尝试修改了
User-Agent字段,但问题还是没解决
首次请求代码
String parameters="parameter=example1"; URL url = new URL("http://example1"); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); conn.setRequestProperty("Content-Length", parameters + Integer.toString(parameters.getBytes().length)); conn.setRequestProperty("Content-Language", "en-US"); conn.setRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); conn.setRequestProperty("User-Agent","Mozilla/5.0 "); conn.setUseCaches(false); conn.setDoInput(true); conn.setDoOutput(true);
第二次请求代码
String parameters1="paramters=example2&token="+token; URL url1 = new URL("https://example1/form"); HttpURLConnection conn1 = (HttpURLConnection)url1.openConnection(); conn1.setRequestMethod("POST"); conn1.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); conn1.setRequestProperty("Content-Length", parameters1 + Integer.toString(parameters1.getBytes().length)); conn1.setRequestProperty("Content-Language", "en-US"); conn1.setRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); conn1.setRequestProperty("User-Agent","Mozilla/5.0");
第二次请求响应头
Status 200
Server: Apache-Example/1.1
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Cteonnt-Length: 6923
Cneonction: close
Date: Sat, 27 Jan 2018 13:23:53 GMT
Connection: keep-alive
Vary: Accept-Encoding
Set-Cookie: JSESSIONID=example; Path=/;
X-Android-Sent-Millis: 1517059396002
X-Android-Received-Millis: 1517059396187
X-Android-Response-Source: NETWORK 200
问题分析与解决方案
我整理了几个最可能的原因和对应的解决办法,你可以逐一尝试:
1. 未携带会话Cookie(最核心原因)
从响应头能看到服务器返回了JSESSIONID,这是会话标识。第一次请求后服务器已经为你创建了会话,但第二次请求没携带这个Cookie,服务器会认为是新的陌生请求,触发浏览器检测。
- 第一次请求完成后,获取响应头里的
Set-Cookie值保存起来 - 第二次请求时,在请求头里添加
Cookie字段,把保存的值传进去
示例代码:
// 第一次请求后提取Cookie String sessionCookie = conn.getHeaderField("Set-Cookie"); // 第二次请求时添加Cookie conn1.setRequestProperty("Cookie", sessionCookie);
2. Content-Length设置错误
你代码里的Content-Length写法明显有问题,把参数字符串和长度拼在一起了,服务器根本无法正确解析请求体:
// 错误写法 conn.setRequestProperty("Content-Length", parameters + Integer.toString(parameters.getBytes().length));
改成正确的写法,直接传入请求体的字节长度:
byte[] postData = parameters.getBytes(StandardCharsets.UTF_8); conn.setRequestProperty("Content-Length", Integer.toString(postData.length));
3. User-Agent过于简陋
单纯的Mozilla/5.0太容易被识别为非真实浏览器,建议用一个完整的现代浏览器UA,比如:
conn1.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
4. 缺少必要的请求头
真实浏览器发送请求时还会携带Referer、Accept-Encoding等字段,你可以补充上这些头信息,让请求更接近真实浏览器行为:
conn1.setRequestProperty("Referer", "http://example1"); // 填写第一次请求的URL conn1.setRequestProperty("Accept-Encoding", "gzip, deflate, br"); conn1.setRequestProperty("Connection", "keep-alive");
5. 请求体未正确发送
检查两次请求是否都正确写出了请求体,如果没发送请求体,服务器可能没有生成有效的token,或者会话不完整:
// 第一次请求发送请求体示例 OutputStream os = conn.getOutputStream(); os.write(postData); os.flush(); os.close();
内容的提问来源于stack exchange,提问作者filipemelo032

