本文目录导读:

你遇到的 ConnectionPendingException 异常,通常发生在使用 JEditorPane 或 HTMLEditorKit 加载远程 HTML 内容时,底层网络连接(如 HTTP 或 HTTPS)由于过慢、被阻塞或无法建立而导致超时或中断。
这个问题在 Java Swing 应用中较为常见,尤其是当网络请求涉及大量资源、超时配置不正确或网络环境不稳定时。
以下是该问题的原因分析及解决方案:
核心原因
- 网络超时:默认的
HttpURLConnection或底层 socket 连接超时,但HTMLEditorKit的解析器(Parser)没有正确处理该异常。 - 连接挂起:服务器没有响应(例如服务器过载、DNS 解析挂起),导致连接一直处于
pending状态。 - 代理问题:如果应用处于代理环境但未正确配置代理。
- 死锁或阻塞:在 Swing 事件调度线程(EDT,Event Dispatch Thread)中直接进行网络加载,导致 UI 线程阻塞,进而引发连接超时或挂起。
- HTTPS 证书问题:某些不安全的 HTTPS 连接会导致连接失败,但错误被包装为
ConnectionPendingException。
解决方案
设置连接超时(推荐)
通过自定义 EditorKit 或修改 JEditorPane 的底层连接属性,设置明确的连接和读取超时时间。
import javax.swing.*;
import javax.swing.text.html.*;
import java.net.URL;
import java.net.URLConnection;
public class SafeHtmlViewer {
public static void main(String[] args) {
JFrame frame = new JFrame();
JEditorPane editorPane = new JEditorPane();
editorPane.setEditable(false);
editorPane.setContentType("text/html");
// 使用自定义 HTMLEditorKit 以控制连接
HTMLEditorKit kit = new HTMLEditorKit() {
@Override
public Document createDefaultDocument() {
HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
// 增加一个自定义的异步加载器
doc.setAsynchronousLoadPriority(0); // 0 表示同步加载,但更建议在后台线程加载
return doc;
}
};
editorPane.setEditorKit(kit);
// 在后台线程加载页面,避免阻塞 EDT
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
URL url = new URL("https://your-slow-website.com");
URLConnection conn = url.openConnection();
// 关键设置:连接和读取超时
conn.setConnectTimeout(5000); // 5秒连接超时
conn.setReadTimeout(5000); // 5秒读取超时
// 设置到 JEditorPane
editorPane.setPage(conn.getURL());
return null;
}
@Override
protected void done() {
// 更新 UI(可选)
}
};
worker.execute();
frame.add(new JScrollPane(editorPane));
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
禁用自动异步加载(关键)
HTMLEditorKit 默认会使用异步加载来获取图片和 CSS,如果网络慢,这可能会导致解析器挂起。设置 asynchronousLoadPriority 为 -1 来完全禁用异步加载,或者设置为 0 强制同步。
// 在你的 HTMLEditorKit 中 HTMLDocument doc = (HTMLDocument) editorPane.getDocument(); // 关键:禁用异步加载,避免连接挂起 doc.setAsynchronousLoadPriority(-1);
使用 S 外部 HttpClient + 流式加载
如果你需要更精细的连接控制(如 Proxy、认证),最可靠的方式是不使用 JEditorPane.setPage(),而是自己通过 HttpURLConnection 或 Apache HttpClient 下载 HTML 内容字符串,然后通过 setText() 设置到 JEditorPane。
SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
@Override
protected String doInBackground() throws Exception {
URL url = new URL("https://example.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
// 读取响应
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
return content.toString();
}
}
@Override
protected void done() {
try {
String htmlContent = get();
// 设置到 JEditorPane,此时完全基于本地字符串,不会有网络连接问题
editorPane.setText(htmlContent);
// 注意:setText 后需要移到光标位置或触发布局
editorPane.setCaretPosition(0);
} catch (Exception e) {
// 处理异常(如超时)
editorPane.setText("<html><body>加载失败:" + e.getMessage() + "</body></html>");
}
}
};
worker.execute();
重要提示
- 永远不要在 EDT 中执行网络操作:即使是
JEditorPane.setPage()看似一行代码,内部也会发起网络请求,如果不使用SwingWorker或Thread,UI 会冻结,进而导致连接挂起。 - 检查你的 HTML 内容是否引用了不可达的外部资源(CSS、JS、图片)?即使主页面加载成功,如果引用的资源超时,也可能触发此异常。
HTMLEditorKit的同步/异步加载优先级对这部分资源也会产生影响。 - 如果控制台有 SSL 警告,可能需要导入证书或设置
TrustManager。
| 方案 | 适用场景 | 关键代码 |
|---|---|---|
| 方案一 | 简单的超时问题 | setConnectTimeout(5000) + setReadTimeout(5000) |
| 方案二 | 异步加载资源导致挂起 | doc.setAsynchronousLoadPriority(-1) |
| 方案三 | 需要精细网络控制/代理 | 自己下载 HTML 再 setText() |
最彻底的解决方法是方案三(手动下载 + setText),因为它完全绕过了 HTMLEditorKit 内建的、容易出错的网络连接逻辑。