【问题标题】:Get HTTP Status Code in Android WebView在 Android WebView 中获取 HTTP 状态码
【发布时间】:2022-03-16 01:43:00
【问题描述】:

我正在开发一个在 WebView 中加载网站的 Android 应用,但有时该网站会返回 HTTP 代码 500。

我的问题是:有什么方法可以通过监听器或其他类从 WebView 获取 HTTP 状态码??

我尝试实现 WebViewClient,但无法获取 WebView 收到的 HTTP 状态代码。

【问题讨论】:

  • 你能在 SDK

标签: android http android-webview


【解决方案1】:

这是不可能的(在我写这篇文章的时候)。 onReceiveError() 的文档充其量是模棱两可的,但你看看这个问题,

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

很明显,HTTP 状态代码不会通过该机制报告。开发人员怎么可能写了 WebView 却无法检索 HTTP 状态代码真的让我大吃一惊。

【讨论】:

  • 从 SDK 23 开始,情况不再如此。
  • 不是每个人都想要/可以购买尖端手机。我的许多客户仍然使用 Android 4 或 5,所以是的,未来几年仍将如此。
  • 使用 onReceivedHttpError(...) - 请参阅下面的答案
【解决方案2】:

您可以使用 ajax 加载内容,然后使用 loadDataWithBaseURL 将其放入 webview。

创建一个这样的网页

<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是注入到javascript中的java对象。

addJavascriptInterface(this, "browserObject");

并将其加载到 webView 中。你应该用你的值替换 path/url。

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);

然后像这样处理onAjaxSuccess/onAjaxError:

    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)
    {

    }

现在您可以处理 http 错误了。

【讨论】:

  • 当应用开发者也可以修改相关网站时,您的建议看起来很棒,但如果应用开发者没有控制网站的 HTML/Javascript 怎么办?你把loadWithAjax()放在哪里?谢谢。
  • 你好。好但很长
【解决方案3】:

你可以重写方法 onReceivedHttpError 并且在那里你可以看到状态码:

@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
    super.onReceivedHttpError(view, request, errorResponse);
    int statusCode = errorResponse.getStatusCode();
    // TODO: do your logic..
}

【讨论】:

    【解决方案4】:

    这似乎可以通过 Android M API (https://code.google.com/p/android/issues/detail?id=82069#c7) 中的新回调实现。

    void onReceivedHttpError(WebView 视图,WebResourceRequest 请求, WebResourceResponse errorResponse)

    很遗憾,这很可能在 Android M 之前的设备中不可用。

    【讨论】:

      【解决方案5】:

      实际上,检查 HTTP 状态以查看内容是否可加载到 webview 中并不算太糟糕。假设:您已经设置了 webview,并且您已经有了目标 URL 的字符串......

          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);
      

      在 WebViewClient 的其他地方,关闭进度对话框

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

      【讨论】:

      • 在这种情况下我们不会加载页面两次吗?
      【解决方案6】:

      此时你无法得到正常的HTTP响应码。

      但作为解决方案,如果您可以修改 webapp 服务器端,请使用以下内容:

      在服务器上创建一些 JavaScript 函数,比如riseHttpError

      在android端使用JavaScript接口,当你需要告诉android处理http错误时,只需在服务器上调用Android.riseHttpError()

      Android 将处理此功能,您将能够在 android 端执行所需的操作。

      在我的解决方案中需要得到错误。您可以发送任何您想要的代码。 :)

      当然,这只是另一种方法。所以,可能还有其他更好的解决方案。

      但是如果你可以修改服务器端,我认为,使用URLHandler进行双重请求会更好。

      【讨论】:

        【解决方案7】:

        我认为从 webView 以简单的方式(如果可能的话)获取状态代码是不可能的。

        我的想法是使用 WebViewClient 中的 onReceivedError() 方法(如您所说),并在 WebViewClient 中定义错误(完整的错误列表可在此处获得:http://developer.android.com/reference/android/webkit/WebViewClient.html)并假设例如 504 状态代码等于 WebViewClient。 ERROR_TIMEOUT 等。

        【讨论】:

        • 谢谢,但它不起作用,我实现了那个方法,但 webview 没有触发它。我会尝试另一种方式,如果我能成功,我会在这里为大家发布解决方案。
        • 你在 WebView 对象上调用过 setWebViewClient() 吗?请粘贴您的代码。
        • public class EnlaceWebClient extends WebViewClient { public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){ Log.d("ERROR","Error code:"+Integer.toString(errorCode)); } }
        【解决方案8】:

        实现一个简单 Activity 的完整示例

        对于 API 级别 >= 23

        Java

        public class MainActivity extends AppCompatActivity {
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        
                WebView myWebView = (WebView)findViewById(R.id.webview);
                myWebView.loadUrl("https://www.fñdghd.es");
                myWebView.setWebViewClient(new CustomWebViewClient());
            }
        
            private class CustomWebViewClient extends WebViewClient
            {
                @Override
                public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error)
                {
                    super.onReceivedError(view, request, error);
                    Log.e("MainActivity",(String) error.getDescription());
                    Log.e("MainActivity",String.valueOf(error.getErrorCode()));
        
                    //Todo: Something to define.
                }
            }
        }
        

        用于 Xamarin 或 Maui 的 C#

        public class WebViewActivity : Activity
        {
            protected override void OnCreate(Bundle? savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
        
                // Set our view from the "main" layout resource
                SetContentView(Resource.Layout.activity_webview);
        
                WebView myWebView = (WebView)FindViewById(Resource.Id.webview);
                myWebView.LoadUrl("https://www.google.es");
                myWebView.SetWebViewClient(new CustomWebViewClient());
            }
        }
        
        internal class CustomWebViewClient : WebViewClient
        {
            public override void OnReceivedError(WebView view, IWebResourceRequest request, WebResourceError error)
            {
                base.OnReceivedError(view, request, error);
                Console.WriteLine(error.Description);
                Console.WriteLine(error.ErrorCode);
        
                //Todo: Something to define.
            }
        }
        

        【讨论】:

          【解决方案9】:

          你应该在页面完成后使用它

          @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();
          }
          

          【讨论】:

            猜你喜欢
            • 2018-01-21
            • 1970-01-01
            • 1970-01-01
            • 2011-10-18
            • 2018-10-28
            • 2021-05-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多