WebView处理网页返回的错误码信息
在 Android 开发中,WebView 用于加载网页或 HTML 内容时,可能会遇到各种错误(如网络错误、HTTP 错误码、SSL 错误等)。正确处理这些错误码信息对于提升用户体验和调试问题至关重要。以下是关于 WebView 处理网页返回的错误码信息 的详细中文讲解,涵盖错误类型、处理方法、代码示例、Android 4.4+(基于 Chromium 引擎)的注意事项,以及实践建议。
一、WebView 错误码概述
- 错误类型:
- 网络错误:如无网络连接、DNS 解析失败、超时等。
- HTTP 错误码:如 404(未找到)、403(禁止访问)、500(服务器错误)等。
- SSL 错误:如证书无效、过期或不受信任。
- 资源加载错误:如图片、CSS 或 JavaScript 文件加载失败。
- 错误处理目标:
- 捕获错误码和描述。
- 向用户显示友好的错误提示(如 Toast 或自定义错误页面)。
- 根据错误类型采取适当措施(如重试、切换缓存模式)。
- 关键 API:
WebViewClient.onReceivedError
:处理页面或资源加载错误。WebViewClient.onReceivedHttpError
:处理 HTTP 错误码(API 23+)。WebViewClient.onReceivedSslError
:处理 SSL 错误。- Android 4.4+ 特性:
- 基于 Chromium 引擎,提供更详细的错误信息。
- API 23+(Android 6.0)细化了
onReceivedError
和onReceivedHttpError
。
二、准备工作
- 权限声明:
在AndroidManifest.xml
中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- 布局文件:
在res/layout/activity_main.xml
中添加 WebView:
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- 错误页面(可选):
在assets
目录下创建error.html
用于显示错误:
<!-- assets/error.html -->
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h1>加载失败</h1>
<p id="errorMessage">页面加载出错,请检查网络或稍后重试。</p>
</body>
</html>
三、WebView 错误码处理方法
以下是处理 WebView 中常见的错误码信息的详细方法,结合 WebViewClient
的相关回调。
1. 处理网络错误和通用错误
使用 onReceivedError
捕获页面加载错误(如网络断开、DNS 错误)。
- 代码示例:
import android.os.Bundle;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
// 设置 WebViewClient 处理错误
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
// API 23+,处理详细错误
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String errorMsg = "错误码: " + error.getErrorCode() + ", 描述: " + error.getDescription();
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
Log.e("WebView", errorMsg);
// 加载自定义错误页面
view.loadUrl("file:///android_asset/error.html");
}
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// API 22 及以下,旧版方法
String errorMsg = "错误码: " + errorCode + ", 描述: " + description + ", URL: " + failingUrl;
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
Log.e("WebView", errorMsg);
view.loadUrl("file:///android_asset/error.html");
}
});
// 加载网页
webView.loadUrl("https://example.com");
}
}
- 常见错误码(
WebResourceError.getErrorCode
): ERROR_HOST_LOOKUP
:DNS 解析失败。ERROR_CONNECT
:无法连接到服务器。ERROR_TIMEOUT
:请求超时。ERROR_IO
:IO 异常(如无网络)。- 完整列表见:https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_HOST_LOOKUP
- 说明:
- API 23+:使用
onReceivedError(WebView, WebResourceRequest, WebResourceError)
,提供详细错误信息(如getErrorCode()
和getDescription()
)。 - API 22 及以下:使用旧版
onReceivedError(WebView, int, String, String)
。 - 加载自定义错误页面(如
error.html
)或显示 Toast 提示用户。
2. 处理 HTTP 错误码
使用 onReceivedHttpError
(API 23+)捕获 HTTP 状态码(如 404、500)。
- 代码示例:
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int statusCode = errorResponse.getStatusCode();
String reason = errorResponse.getReasonPhrase();
String errorMsg = "HTTP 错误: " + statusCode + " " + reason;
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
Log.e("WebView", errorMsg);
if (statusCode == 404) {
view.loadUrl("file:///android_asset/error.html");
}
}
}
});
- 常见 HTTP 错误码:
404 Not Found
:页面或资源不存在。403 Forbidden
:无权限访问。500 Internal Server Error
:服务器内部错误。503 Service Unavailable
:服务器不可用。- 说明:
onReceivedHttpError
专门处理 HTTP 响应错误,适用于页面或资源请求。- 可根据状态码(如 404)显示特定错误页面或提示。
3. 处理 SSL 错误
使用 onReceivedSslError
处理 SSL 相关错误(如证书无效)。
- 代码示例:
import android.net.http.SslError;
import android.webkit.SslErrorHandler;
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
String errorMsg = "SSL 错误: " + error.getPrimaryError();
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
Log.e("WebView", errorMsg);
// 提示用户是否继续
new AlertDialog.Builder(MainActivity.this)
.setTitle("SSL 错误")
.setMessage("证书错误,是否继续?")
.setPositiveButton("继续", (dialog, which) -> handler.proceed())
.setNegativeButton("取消", (dialog, which) -> {
handler.cancel();
view.loadUrl("file:///android_asset/error.html");
})
.show();
}
});
- 常见 SSL 错误(
SslError.getPrimaryError
): SSL_UNTRUSTED
:证书不受信任。SSL_DATE_INVALID
:证书过期或未生效。SSL_IDMISMATCH
:主机名不匹配。- 说明:
- 谨慎调用
handler.proceed()
,可能导致安全风险。 - 建议提示用户并默认调用
handler.cancel()
。
4. 处理资源加载错误
资源(如图片、CSS)加载失败时,也会触发 onReceivedError
。
- 代码示例:
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (request.isForMainFrame()) {
// 主页面错误
String errorMsg = "主页面错误: " + error.getDescription();
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
view.loadUrl("file:///android_asset/error.html");
} else {
// 资源错误(如图片、CSS)
Log.w("WebView", "资源错误: " + request.getUrl() + ", " + error.getDescription());
}
}
}
});
- 说明:
- 使用
request.isForMainFrame()
区分主页面和子资源错误。 - 资源错误通常不影响主页面加载,可记录日志而无需提示用户。
5. 检查网络状态
在加载网页前检查网络状态,避免不必要的错误。
- 代码示例:
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo == null || !networkInfo.isConnected()) {
Toast.makeText(this, "无网络连接", Toast.LENGTH_SHORT).show();
webView.loadUrl("file:///android_asset/error.html");
} else {
webView.loadUrl("https://example.com");
}
四、完整代码示例
以下是一个完整的 WebView 示例,处理网络错误、HTTP 错误和 SSL 错误:
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.webkit.SslError;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true); // 谨慎启用
// 设置 WebViewClient 处理错误
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String errorMsg = "错误码: " + error.getErrorCode() + ", 描述: " + error.getDescription();
Log.e("WebView", errorMsg);
if (request.isForMainFrame()) {
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
view.loadUrl("file:///android_asset/error.html");
} else {
Log.w("WebView", "资源错误: " + request.getUrl());
}
}
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// API 22 及以下
String errorMsg = "错误码: " + errorCode + ", 描述: " + description;
Log.e("WebView", errorMsg);
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
view.loadUrl("file:///android_asset/error.html");
}
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int statusCode = errorResponse.getStatusCode();
String reason = errorResponse.getReasonPhrase();
String errorMsg = "HTTP 错误: " + statusCode + " " + reason;
Log.e("WebView", errorMsg);
Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show();
if (statusCode == 404) {
view.loadUrl("file:///android_asset/error.html");
}
}
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
String errorMsg = "SSL 错误: " + error.getPrimaryError();
Log.e("WebView", errorMsg);
new AlertDialog.Builder(MainActivity.this)
.setTitle("SSL 错误")
.setMessage("证书错误,是否继续?")
.setPositiveButton("继续", (dialog, which) -> handler.proceed())
.setNegativeButton("取消", (dialog, which) -> {
handler.cancel();
view.loadUrl("file:///android_asset/error.html");
})
.show();
}
});
// 检查网络状态
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo == null || !networkInfo.isConnected()) {
Toast.makeText(this, "无网络连接", Toast.LENGTH_SHORT).show();
webView.loadUrl("file:///android_asset/error.html");
} else {
webView.loadUrl("https://example.com");
}
}
@Override
protected void onPause() {
super.onPause();
webView.onPause();
webView.pauseTimers();
}
@Override
protected void onResume() {
super.onResume();
webView.onResume();
webView.resumeTimers();
}
@Override
protected void onDestroy() {
if (webView != null) {
webView.stopLoading();
webView.clearCache(true);
webView.loadUrl("about:blank");
webView.removeAllViews();
webView.destroy();
webView = null;
}
super.onDestroy();
}
}
- 布局文件(
res/layout/activity_main.xml
):
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- 错误页面(
assets/error.html
):
<!DOCTYPE html>
<html>
<head>
<title>错误</title>
</head>
<body>
<h1>加载失败</h1>
<p>页面加载出错,请检查网络或稍后重试。</p>
</body>
</html>
- 说明:
- 处理网络错误、HTTP 错误和 SSL 错误。
- 根据错误类型显示 Toast 或加载错误页面。
- 检查网络状态,优化用户体验。
- 包含生命周期管理。
五、注意事项
- Android 4.4+ 特性:
- Chromium 引擎:提供更详细的错误信息(如
WebResourceError
)。 - API 23+:
onReceivedError
和onReceivedHttpError
分离,分别处理网络和 HTTP 错误。 - WebView 更新:Android 5.0+ WebView 可通过 Google Play 更新,需测试版本兼容性:
java String webViewVersion = WebView.getCurrentWebViewPackage().versionName; Log.d("WebView", "WebView Version: " + webViewVersion);
- 安全问题:
- HTTPS:Android 9+ 默认禁用 HTTP,优先使用 HTTPS:
xml <application android:usesCleartextTraffic="false">
- SSL 错误:避免直接调用
handler.proceed()
,提示用户确认。 - JavaScript 安全:启用
setJavaScriptEnabled(true)
时,仅加载受信任内容。
- 性能优化:
- 启用缓存以减少网络请求:
java webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); webView.getSettings().setAppCacheEnabled(true);
- 错误后尝试缓存模式:
java webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
- 生命周期管理:
- 暂停/恢复 WebView:
@Override protected void onPause() { super.onPause(); webView.onPause(); webView.pauseTimers(); } @Override protected void onResume() { super.onResume(); webView.onResume(); webView.resumeTimers(); }
- 销毁 WebView:
java @Override protected void onDestroy() { if (webView != null) { webView.stopLoading(); webView.clearCache(true); webView.loadUrl("about:blank"); webView.removeAllViews(); webView.destroy(); webView = null; } super.onDestroy(); }
- 用户体验:
- 显示友好的错误提示(如 Toast 或错误页面)。
- 提供重试按钮:
xml <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/retryButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="重试" /> <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
java findViewById(R.id.retryButton).setOnClickListener(v -> webView.reload());
六、学习建议与实践
- 学习路径:
- 掌握
WebViewClient
的错误处理方法(onReceivedError
、onReceivedHttpError
、onReceivedSslError
)。 - 了解常见错误码(网络、HTTP、SSL)。
- 实现自定义错误页面和用户提示。
- 测试不同网络环境(如无网络、弱网)。
- 调试 WebView 错误。
- 实践项目:
- 简单项目:加载网页,捕获网络错误并显示 Toast。
- 进阶项目:处理 HTTP 404/500 错误,加载自定义错误页面。
- 高级项目:开发 Hybrid App,结合 REST API 和错误处理。
- 调试工具:
- Chrome DevTools:通过
chrome://inspect
调试 WebView,查看网络请求和错误。 - Charles/Fiddler:抓包分析 HTTP 错误码。
- Logcat:记录错误日志。
- Android Studio Network Profiler:监控网络请求。
- 推荐资源:
- Android 官方文档:https://developer.android.com/reference/android/webkit/WebViewClient
- WebView 错误码:https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_HOST_LOOKUP
- SSL 错误:https://developer.android.com/reference/android/net/http/SslError
七、总结
- 错误类型:
- 网络错误:DNS 失败、超时等,使用
onReceivedError
。 - HTTP 错误:404、500 等,使用
onReceivedHttpError
(API 23+)。 - SSL 错误:证书问题,使用
onReceivedSslError
。 - 处理方法:
- 捕获错误码和描述,记录日志。
- 显示友好的提示或错误页面。
- 检查网络状态,尝试缓存或重试。
- Android 4.4+ 注意:
- Chromium 引擎提供更详细错误信息。
- API 23+ 细化错误处理。
- 测试 WebView 版本兼容性。
- 推荐:
- 优先使用 HTTPS,谨慎处理 SSL 错误。
- 结合错误页面和用户提示提升体验。
- 使用 Chrome DevTools 调试。
如果需要更详细的代码示例(如复杂错误处理、自定义错误 UI)或特定场景的讲解,请告诉我!