HttpUrlConnection 出现 503 错误,但网站在浏览器上加载

Getting 503 error with HttpUrlConnection but site loading on browser

     url = "https://www.lmcu.org/?__cf_chl_jschl_tk__=9c114404052361017d9cfe1247981e24813649c7-1592389426-0-AfP07ha5TxZHf64q5tb5nJf9BJguC4U553-OJzJWivTqfgwYLqUODkXj-XsOjZTwpC71ROxHWx4Xhdp2S0LgAVlKgXpy7KWOex7lkoGBm8mNpBsCeJapdYNWty-X2oHE6gp_TtMfH0dcBabvWr_mXV1djsVR_IGlYJA-wCuZpPTGOozyzN9TFwjMPxU-3o6BIUxTh6DDcHmJ_Bw48EYKGpq6n57bVdeLezEs9PduataW1JUcF4GqLE2EHiUxWGubtS8YgcxkkGin4zitHXENMbFi1kMhxI77LsORzKyhkAD1OkG8fGmV--Cgd3EpxWHtHD5vpoIFFIwX0uGQywPnegs";

     HttpURLConnection connection = pingHttpUrl(url);
     responseCode = connection.getResponseCode();

     public HttpURLConnection pingHttpUrl(String url) throws IOException {

        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("GET");

            conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76 Safari/537.36");
            conn.setConnectTimeout(2000);
            conn.setInstanceFollowRedirects(false);
            conn.setReadTimeout(10000);
            conn.connect();
            Thread.sleep(1000);
        } catch (Exception e) {
            logger.error("Caught exception : {}", e.getMessage());
            throw new IOException();
        }

        return conn;
     }

这给出的响应代码为 503。但该网站正在浏览器上正确加载。这可能是什么问题?

问题出在请求的 header 上。我发现这个托管在 cloudflare 上的解决方案需要两个 header 才行,否则你会收到 503 响应:

  • User-Agent - 你的header指定了chrome版本76,显然服务器有这有问题。我在这个 User-Agent 值上取得了成功:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
  • cookie - 我发现需要设置 cookie 值 cf_clearance,并且可能在第一次请求时返回其他 set-cookie 值.此值与 cloudflare 对隐私通行证的支持有关 (https://blog.cloudflare.com/cloudflare-supports-privacy-pass/)。它似乎是一种验证用户是人而不是机器的方法。这反过来对你在这里的努力来说是个坏消息。

我在下面有一个可行的解决方案,但它很难自动化 - 因为它需要您建立一个浏览器 session,并使用代码中设置的 cookie。 cf_clearance cookie 过期后,您将再次访问该站点并在代码中重置 cookie 值。

我还推测请求的 User-Agent header 用于生成所需的 cf_clearance cookie。使劫持 cookie 变得更加困难,因为当 cloudflare 生成 cf_clearance cookie 时,您必须使用用于请求的浏览器的匹配 User-Agent。

我在这里记录了我的调查:

在我的浏览器中访问 URL 时:

https://www.lmcu.org/?cf_chl_jschl_tk=9c114404052361017d9cfe1247981e24813649c7-1592389426-0-AfP07ha5TxZHf64q5tb5nJf9BJguC4U553-OJzJWivTqfgwYLqUODkXj-XsOjZTwpC71ROxHWx4Xhdp2S0LgAVlKgXpy7KWOex7lkoGBm8mNpBsCeJapdYNWty-X2oHE6gp_TtMfH0dcBabvWr_mXV1djsVR_IGlYJA-wCuZpPTGOozyzN9TFwjMPxU-3o6BIUxTh6DDcHmJ_Bw48EYKGpq6n57bVdeLezEs9PduataW1JUcF4GqLE2EHiUxWGubtS8YgcxkkGin4zitHXENMbFi1kMhxI77LsORzKyhkAD1OkG8fGmV--Cgd3EpxWHtHD5vpoIFFIwX0uGQywPnegs

并检查服务器给出的响应,事实证明它实际上也在返回 503

由于某些我无法理解的原因,浏览器被重定向到下面的 URL。我无法在响应中看到位置 header 被传回,也无法在响应中的任何位置找到此 URL。

https://www.lmcu.org/?cf_chl_jschl_tk=fe835fdc1e7e2f5b2857ab5eb4be84e67d0e8c42-1592506549-0-AQ3E1piNGHg7O7lxgRyItR1U5BzB52q7GmCHe_HPJBsUHv8RcZCgqLPPtyngPmDjvy7pZDprPNK6ihKVEgQ7HqmbDSPXZ1aHPkBDs9re49u_Q_jI04etmtK7E0GIdxhKWCd-p4TR7b_b0JdnwzJOF6z4XaJQOgNU8kazJr5Mo96zxQpUlsKWPSumEmSfynkGeMDgkM-O1mN59LKp0p4kt-2O2IIFrlc8289ZbCSO6JghtvDsLsFDA3VxLV3Irn2W3KQ8sHg_TdwB-0g0WX9J-WTwedVYzj2a7uNtH377ZIritTXKqRw1qeQ6mkpxQ0h_OVMIl8XUiEC0Zj1KP50tUK8

我与 Postman 核对过,果然 - 我在那里也遇到了 503 错误。据我所知,服务器(或它前面的反向代理)正在检查请求的 headers,并根据它们使请求无效。我胡闹了一点,将 headers 从浏览器请求移到 Postman 中,最后发现它是 cookieUser-Agent headers 的组合允许请求被送达。

User-Agent header 不允许有指定的 chrome 版本,我这里使用的是 83 版本。 cookkie header 是我第一次在浏览器中访问该站点时浏览器将填充的内容。所以在你的代码中处理起来有点困难。我试图用 connection.getHeaderField("set-cookie") 在代码中获取它,但那个 cookie 似乎并没有削减它。

但是!当从我的浏览器中获取 cookie 并在代码中手动设置它以及 User-Agent:

时,我能够使代码工作
    public HttpURLConnection pingHttpUrl(String url) throws IOException {

        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("GET");

            // This one does not work for the reason of the chrome version apparently
            // conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76 Safari/537.36");
            conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36");
            conn.addRequestProperty("cookie", "<cookie value from the browser, from the header on a successful request>");

            conn.setConnectTimeout(2000);
            conn.setInstanceFollowRedirects(false);
            conn.setReadTimeout(10000);
            conn.connect();
            Thread.sleep(1000);
        } catch (Exception e) {
            System.out.println(String.format("Caught exception : %s", e.getMessage()));
            throw new IOException();
        }

        return conn;
    }

我后来发现是来自 cookie 中 cf_clearance 键的 cookie 值造成了差异。