【问题标题】:JavaFX WebView does not load pageJavaFX WebView 不加载页面
【发布时间】:2019-02-13 12:53:03
【问题描述】:

我正在尝试打开 "engine.load("https://login.microsoftonline.com");"在 JavaFX Web 视图中。

当使用 jdk1.8.0_161 时页面被加载。使用 jdk1.8.0_181 时页面无法加载。它显示空窗口并且不返回任何错误: engine.getLoadWorker().exceptionProperty() 为空。

您知道 Java 的新版本更新中可能发生了什么变化吗?我在 Java 10 最新版本上进行了测试,页面也没有加载。 此代码适用于 JDK8.161 和 JDK9.0.4,但不适用于 JDK8.181 和 JDK10.0.2

这是我创建的示例应用的源代码:

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.embed.swing.JFXPanel;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebErrorEvent;
import javafx.scene.web.WebEvent;
import javafx.scene.web.WebView;
import javafx.util.Callback;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.swing.*;

import org.w3c.dom.Document;

public class LoginApplicationWindow {

    public static void main(String args[]) {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(620, 440);
        final JFXPanel fxpanel = new JFXPanel();
        frame.add(fxpanel);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                WebEngine engine;               
                WebView wv = new WebView();
                engine = wv.getEngine();
                engine.setJavaScriptEnabled(true);

                 // Create a trust manager that does not validate certificate chains
                TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        // TODO Auto-generated method stub
                        return null;
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        // TODO Auto-generated method stub

                    }
                }};

                // Install the all-trusting trust manager
                SSLContext sc;
                try {
                    sc = SSLContext.getInstance("SSL");
                    sc.init(null, trustAllCerts, new java.security.SecureRandom());
                    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
                } catch (NoSuchAlgorithmException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (KeyManagementException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }


                // Create all-trusting host name verifier
                HostnameVerifier allHostsValid = new HostnameVerifier() {

                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        // TODO Auto-generated method stub
                        return true;
                    }
                };

                // Install the all-trusting host verifier
                HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

                engine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
                      public void changed(ObservableValue ov, State oldState, State newState) {
                        if (newState == State.SUCCEEDED) {
                          Document doc = engine.getDocument();
                          // operations on dom occur here.
                          System.out.println(engine.getLoadWorker().exceptionProperty());
                          System.out.print("load finished " + doc.getBaseURI());
                        }
                      }
                });


                engine.setOnAlert(new EventHandler<WebEvent<String>>() {

                    @Override
                    public void handle(WebEvent<String> event) {
                        System.out.print("setOnAlert " + event.getData());
                    }
                });

                engine.setOnError(new EventHandler<WebErrorEvent>() {

                    @Override
                    public void handle(WebErrorEvent event) {
                        System.out.print("onError " + event.getMessage());
                    }
                });

                engine.setConfirmHandler(new Callback<String, Boolean>() {

                    @Override
                    public Boolean call(String param) {
                        // TODO Auto-generated method stub
                        System.out.print("setConfirmHandler " + param);
                        return null;
                    }
                });


                fxpanel.setScene(new Scene(wv));
                engine.load("https://login.microsoftonline.com");
                //engine.load("https://facebook.com");

            }
        });
        frame.setVisible(true);
    }
}

【问题讨论】:

  • A comment on a related question's answer on how to trust all certificates on SSL 注意到X509TrustManager getAcceptedIssuers() Javadoc 需要返回一个非空数组。您返回 null 而不是空数组。也许这个规范最初并没有被强制执行,但是在这些 Java 版本之间的某个时候它被强制执行了。尝试更改此设置。
  • 嗯,这肯定不是问题。我尝试返回一个空数组,结果是一样的。没有显示页面。我没有收到 SSL 错误。我没有收到任何错误,只有 empy page.. 这是屏幕上次重定向到的 url:
  • 我已经在这四个 JDK 中分别测试了您的代码,以确认这确实是 JDK 问题而不是系统问题。我不知道为什么在某些 JDK 中会出现此问题,而在其他 JDK 中则不会。奇怪。
  • 比较 JRE/lib/security 文件夹中的 java.security 文件。我的感觉是 security.providers 的顺序已经改变(一旦我们得到这个惊喜)或者一些 SSL 相关的设置已经改变。

标签: java swing javafx java-8 javafx-webview


【解决方案1】:

事实证明,任何网络问题(DNS/连接)都可能导致错误,并且加载不会引发任何适当的异常。 好消息是,如果你替换 .load(url) 调用,至少你会在日志中看到问题。

在替换时,我的意思是将网站单独加载到字符串中

private static String getData(String address) throws Exception {
    URL page = new URL(address);
    StringBuffer text = new StringBuffer();
    HttpURLConnection conn = (HttpURLConnection) page.openConnection();
    conn.connect();
    try (InputStreamReader in = new InputStreamReader(
            (InputStream) conn.getContent())) {
        BufferedReader buff = new BufferedReader(in);
        String line;
        do {
            line = buff.readLine();
            text.append(line + "\n");
        } while (line != null);
        return text.toString();
    } finally {
        conn.disconnect();
    }
}

并替换 .load:

    //engine.load("https://login.microsoftonline.com");
    engine.loadContent(getData("https://login.microsoftonline.com"));

当然,应该正确捕获和记录异常。 (有趣的是,引用的资源(images/js/css 什么文件)也会以这种方式很好地加载。)

【讨论】:

  • 所以这不是 SSL 问题。我尝试将内容下载为字符串,我得到了它。但是当我尝试将它放在带有 loadContent 的 webview 中时,我得到了空屏幕。如果我在 loadContent 中设置任何其他 HTML 有效字符串,它就会被加载...
  • 嗯,我没有用你的 URL 测试解决方案。我在家里做了,似乎这个网站使用了 Oauth2,也可能使用了框架,或者可能是 javascript 是它不起作用的原因(我只有一个 null)。 here 您可以阅读有关可用的 java 浏览器的比较,也许您应该切换到另一个实现。另一种选择是手动执行 oauth2,但我认为这太痛苦了。
猜你喜欢
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 2013-05-07
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多