Android 出现Http 302跳转问题

Android 出现Http 302跳转问题

最近在做一个网络诊断功能,检测外网连通性,测试地址是http://www.baidu.com。

问题出现

测试方法:
HttpURLConnection进行网络连接访问,根据访问返回的http状态码是否为200,确定外网是否连通。测试代码:

               int resCode = -1;
                    try {
                        URL url = new URL(urlStr);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        //信任https站点
                        if (conn instanceof HttpsURLConnection) {
                            HttpsURLConnection conns = (HttpsURLConnection) conn;
                            conns.setHostnameVerifier(new HostnameVerifier() {

                                @Override
                                public boolean verify(String hostname, SSLSession session) {
                                    return true;
                                }
                            });
                            SSLContext sslCtx = SSLContext.getInstance("SSL");
                            sslCtx.init(null, new TrustManager[]{new XulWorker.acceptAllTrustManager()}, new SecureRandom());
                            if (sslCtx != null) {
                                conns.setSSLSocketFactory(sslCtx.getSocketFactory());
                            }
                        }
                        conn.setRequestMethod("GET");
                        conn.setConnectTimeout(timeoutMillis);
                        conn.connect();
                        resCode = conn.getResponseCode(); // 获取get请求responseCode
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if (callback != null) {
                            callback.compareTo((resCode == 200 ? 0 : -1) == 0);
                        }
                   }

测试结果:
大部分设备上该方式处理没有问题,在极少的几个设备上,发现永远是非200的状态码。但是本身也是可以连接外网的,访问没有问题。
分析:
通过打印状态码,发现状态码为302错误。那302错误大家都应该很熟悉了,就是访问地址被移出到另外的地址了,需要重新访问另外的地址。
举个例子:
在浏览器输入http://www.sogou.com,进行抓包或者通过浏览器F12查看network访问,如下图,
302示例访问

访问http://www.sogou.com后,服务器吐回状态码302 ,然后Locatioin字段标识浏览器应该跳转到了 。
302跳转地址

那之前的代码健壮性不强,没有考虑到302跳转场景,怎么来规避呢?

解决办法

开始时候,想的是使用简单的方式达到效果,翻阅了的HttpsURLConnection 类的所有方法,存在这个方法:

 /**
     * Sets whether this connection follows redirects.
     *
     * @param followRedirects
     *            {@code true} if this connection will follows redirects, false
     *            otherwise.
     */
    public void setInstanceFollowRedirects(boolean followRedirects) {
        instanceFollowRedirects = followRedirects;
    }

从这个方法来看,貌似是可以设置是否支持重定向访问,所以这样设置:
conn.setInstanceFollowRedirects(true);
结果,访问302的地址还是失败,根本不会自动跳转访问。也不清楚具体原因,估计要看源码了,所以换了方式处理该问题;

方式1: 解析http请求返回的Location,进行重新访问请求
示例代码:

        private static int reload(String urlStr, int timeoutMillis) throws Exception {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //信任https站点
            if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection conns = (HttpsURLConnection) conn;
                conns.setHostnameVerifier(new HostnameVerifier() {

                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
                SSLContext sslCtx = SSLContext.getInstance("SSL");
                sslCtx.init(null, new TrustManager[]{new XulWorker.acceptAllTrustManager()}, new SecureRandom());
                if (sslCtx != null) {
                    conns.setSSLSocketFactory(sslCtx.getSocketFactory());
                }
            }
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(timeoutMillis);
            conn.connect();


            if (huc.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP
                    || huc.getResponseCode() == HttpURLConnection.HTTP_MOVED_PERM)// 302, 301
                return reload(huc.getHeaderField("location"), timeoutMillis);

            return huc.getResponseCode();
        }

方式2:使用AndroidHttpClient进行网络访问
通过设置ClientPNames.HANDLE_REDIRECTS为true,来达到重定向请求功能。
ps:DefaultHttpClient是默认支持http get的重定向访问,也可以直接用该类实现请求。post还是不支持的。

    public static int getResponseCode(String urlStr, int timeoutMillis) {
        int resCode = -1;
        try {
            AndroidHttpClient httpClient = AndroidHttpClient.newInstance("Network check");
            //兼容服务器端重定向url
            HttpParams params = httpClient.getParams();
            params.setParameter(ClientPNames.HANDLE_REDIRECTS, true);
            HttpConnectionParams.setSoTimeout(params, timeoutMillis);

            HttpGet get_url = new HttpGet(urlStr);
            HttpResponse response = httpClient.execute(get_url);
            StatusLine statusLine = response.getStatusLine();
            resCode = statusLine.getStatusCode();
            Logger.d(TAG, "isNetWorkAvailableOfGet() called resCode: "+resCode +"," + urlStr );
        } catch (Exception e) {
            Logger.d(TAG, "isNetWorkAvailableOfGet() Exception: "+ e.getMessage() +"," + urlStr);
            e.printStackTrace();
        } finally {
            return resCode;
        }
    }

结论

302跳转本身是比较常见的一种访问访问结果,在写网络请求时候,需要考虑,并且选择合适的方式来处理,增强代码健壮性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值