如何解决java.net.ProtocolException:服务器重定向次数过多问题?
解决Java访问InformedDelivery时的重定向过多问题
出现java.net.ProtocolException: Server redirected too many times (20)的核心原因是你的请求未通过USPS的认证流程,服务器反复将请求重定向到登录页面,最终触发重定向次数上限。USPS的InformedDelivery不支持直接用Basic Auth认证,你需要模拟浏览器的完整登录流程:
关键修复点
- 先发起GET请求获取登录页面的Cookie和必要认证参数(如CSRF令牌)
- 提交登录表单时使用POST,携带正确的表单数据(而非Basic Auth请求头)
- 确保Cookie在整个会话中持续传递
修改后的代码示例
import java.io.*; import java.net.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class GetMailStatus { public static void main(String[] args) { CookieManager cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL); CookieHandler.setDefault(cookieManager); try { // 第一步:获取登录页面,提取Cookie和CSRF令牌 URL loginPageUrl = new URL("https://informeddelivery.usps.com/login"); HttpURLConnection loginPageConn = (HttpURLConnection) loginPageUrl.openConnection(); loginPageConn.setRequestMethod("GET"); loginPageConn.connect(); // 读取页面内容,提取CSRF令牌(需根据实际页面结构调整正则) String loginPageContent = readInputStream(loginPageConn.getInputStream()); Pattern csrfPattern = Pattern.compile("<input type=\"hidden\" name=\"csrfToken\" value=\"([^\"]+)\""); Matcher matcher = csrfPattern.matcher(loginPageContent); String csrfToken = ""; if (matcher.find()) { csrfToken = matcher.group(1); } loginPageConn.disconnect(); // 第二步:提交登录表单 URL loginPostUrl = new URL("https://informeddelivery.usps.com/login/submit"); HttpURLConnection loginPostConn = (HttpURLConnection) loginPostUrl.openConnection(); loginPostConn.setRequestMethod("POST"); loginPostConn.setDoOutput(true); loginPostConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); loginPostConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); // 构造表单数据(替换为你的实际用户名和密码) String formData = "username=xxxx&password=yyyy&csrfToken=" + csrfToken + "&rememberMe=false"; try (OutputStream os = loginPostConn.getOutputStream()) { byte[] input = formData.getBytes("utf-8"); os.write(input, 0, input.length); } // 处理登录后的重定向,访问目标页面 int responseCode = loginPostConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_MOVED_PERM) { String redirectUrl = loginPostConn.getHeaderField("Location"); URL targetUrl = new URL(redirectUrl); HttpURLConnection targetConn = (HttpURLConnection) targetUrl.openConnection(); targetConn.setRequestMethod("GET"); targetConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); String targetContent = readInputStream(targetConn.getInputStream()); System.out.println(targetContent); targetConn.disconnect(); } loginPostConn.disconnect(); } catch (Exception e) { e.printStackTrace(); } } private static String readInputStream(InputStream is) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line; while ((line = br.readLine()) != null) { sb.append(line).append("\n"); } br.close(); return sb.toString(); } }
额外注意事项
- CSRF令牌适配:实际登录页面的CSRF令牌字段名可能不同,需用浏览器开发者工具查看表单结构,调整正则表达式
- HTTPS证书:若遇到证书信任问题,可临时添加信任所有证书的逻辑(生产环境不建议)
- 用户代理模拟:添加
User-Agent请求头模拟浏览器行为,避免被服务器识别为爬虫 - 会话验证:登录后可通过检查响应内容或状态码,确认是否成功进入目标页面
内容的提问来源于stack exchange,提问作者Cardsfan
相关产品推荐
相关产品推荐

