Get HTTP Status Code in Android WebView

2019-01-11 17:11发布

问题:

I'm developing an Android app that loads a website in a WebView, but sometimes the website returns HTTP code 500.

My question is: is there any way to get the HTTP status code from a WebView with a listener or with another class??

I tried to implement an WebViewClient, but I couldn't get the HTTP status code which WebView received.

回答1:

It's not possible (as of the time i'm writing this). The docs for onReceiveError() are ambiguous at best, but it you look at this issue,

http://code.google.com/p/android/issues/detail?id=968

It's clear that HTTP status codes won't be reported through that mechanism. How it's possible that the developers wrote WebView with no way to retrieve the HTTP status code really blows my mind.



回答2:

You can load content with ajax and then just put it into the webview with loadDataWithBaseURL.

Create a web page like this

<script type="text/javascript">
    function loadWithAjax() {
        var httpRequest = new XMLHttpRequest();
        var path = 'PATH';
        var host = 'HOST';
        var url = 'URL';

        httpRequest.onreadystatechange = function(){
            if (httpRequest.readyState === 4) { 
                if (httpRequest.status === 200) {
                    browserObject.onAjaxSuccess(host, url, httpRequest.responseText);
                } else {
                    browserObject.onAjaxError(host, url, httpRequest.status);
                }
            }
        };

        httpRequest.open('GET', path, true);
        httpRequest.send(null);
    }
</script>
<body onload="loadWithAjax()">

browserObject is java object injected into javascript.

addJavascriptInterface(this, "browserObject");

And load it into webView. You should replace path/url with your values.

ajaxHtml = IOUtils.toString(getContext().getAssets().open("web/ajax.html"));
            ajaxHtml = ajaxHtml.replace("PATH", path);
            ajaxHtml = ajaxHtml.replace("URL", url);
            ajaxHtml = ajaxHtml.replace("HOST", host);

loadDataWithBaseURL(host, ajaxHtmlFinal, "text/html", null, null);

Then handle onAjaxSuccess/onAjaxError like this:

    public void onAjaxSuccess(final String host, final String url, final String html)
    {
        ((Activity) getContext()).runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                loadDataWithBaseURL(url, html, "text/html", null, null);
            }
        });
    }

    public void onAjaxError(final String host, final String url, final int errorCode)
    {

    }

Now you can handle http errors.



回答3:

Actually it's not too bad to check HTTP status to see if content is available to load into a webview. Assumed: You've already set your webview and you have the string for your target URL then...

    AsyncTask<Void, Void, Void> checkURL = new AsyncTask<Void, Void, Void>() {
        @Override
        protected void onPreExecute() {
            pd = new ProgressDialog(WebActivity.this, R.style.DickeysPDTheme);
            pd.setTitle("");
            pd.setMessage("Loading...");
            pd.setCancelable(false);
            pd.setIndeterminate(true);

            pd.show();
        }
        @Override
        protected Void doInBackground(Void... arg0) {
            // TODO Auto-generated method stub
            int iHTTPStatus;

            // Making HTTP request
            try {
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpGet httpRequest = new HttpGet(sTargetURL);

                HttpResponse httpResponse = httpClient.execute(httpRequest);
                iHTTPStatus = httpResponse.getStatusLine().getStatusCode();
                if( iHTTPStatus != 200) {
                    // Serve a local page instead...
                    wv.loadUrl("file:///android_asset/index.html");
                }
                else {

                    wv.loadUrl(sTargetURL);     // Status = 200 so we can loard our desired URL
                }

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                // Show a toast for now...
                Toast.makeText(WebActivity.this, "UNSUPPORTED ENCODING EXCEPTION", Toast.LENGTH_LONG).show();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
                // Show a toast for now...
                Toast.makeText(WebActivity.this, "CLIENT PROTOCOL EXCEPTION", Toast.LENGTH_LONG).show();

            } catch (IOException e) {
                e.printStackTrace();
                // Show a toast for now...
                Toast.makeText(WebActivity.this, "I/O EXCEPTION", Toast.LENGTH_LONG).show();

            }  catch (Exception e) {
                e.printStackTrace();
                // Show a toast for now...
                Toast.makeText(WebActivity.this, "GENERIC EXCEPTION", Toast.LENGTH_LONG).show();

            }

            return null;
        }


    };

    checkURL.execute((Void[])null);

Elsewhere, in WebViewClient, dismiss the progress dialog

@Override  
    public void onPageFinished(WebView view, String url)  
    {
        // Do necessary things onPageFinished
        if (pd!=null) {
            pd.dismiss();
        }

    }       


回答4:

It looks as though this is possible via a new callback in the Android M API (https://code.google.com/p/android/issues/detail?id=82069#c7).

void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse)

Unfortunately, this will most likely not available in pre-Android M devices.



回答5:

At this time you cannot get normal HTTP response code.

But as solution, if is possible to you to modify webapp server side, to use following:

On the server create some JavaScript function, let's say, riseHttpError.

On android side use JavaScript interface and when you need to tell android to handle http error, just call Android.riseHttpError() on server.

Android will handles this function and you will be able to do required actions on android side.

In my solution were required to get errors. You can send any code you want. :)

Of course, this is just another variation how to do it. So, probably there is others, much better solutions.

But if you can modify server side, I think, this will be better to do double request using URLHandler.



回答6:

I don't think it is possible to get status code in easy way(if it's at all possible) from webView.

My idea is to use onReceivedError() method from WebViewClient(as you said) with defined errors in WebViewClient (full list of errors is available here: http://developer.android.com/reference/android/webkit/WebViewClient.html) and assume that for instance 504 status code is equals to WebViewClient.ERROR_TIMEOUT etc.



回答7:

You should use this after the on Page finished

@Override 
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){
    //Your code to do
    Toast.makeText(
        getActivity(), 
        "Your Internet Connection May not be active Or " + error,
        Toast.LENGTH_LONG
    ).show();
}