当 url 包含本地文件的片段时,Javafx getHostServices().showDocument 不起作用

Awk*_*k11 3 java javafx kotlin url-fragment

我正在开发一个 javafx 应用程序,要求是单击超链接时,它会在浏览器中打开给定的 url。我有这个与以下工作

url = "files/file.html";
getHostServices().showDocument(url);
Run Code Online (Sandbox Code Playgroud)

但是,当 url 包含自动聚焦页面特定部分的 id 时,浏览器永远不会启动。没有错误,似乎没有记录任何内容表明出现任何问题,浏览器永远不会打开。无法找到遇到此问题的其他人或任何潜在的解决方案。

太棒了;如何让以下内容实际工作并在浏览器中打开?

String url = "files/file.html#section";
getHostServices().showDocument(url);
Run Code Online (Sandbox Code Playgroud)

另外,这似乎只是本地文件的问题。以这种方式打开 https 网站效果很好

更新: 感谢 Sai 的精彩帖子,听起来官方的结论是,这是一个比 Java 更深层次的问题,并且只是出于与数据注入相关的安全原因而被阻止。不会假装理解,但我找到了一个基于此链接的解决方案(再次由 Sai 在下面共享),更具体地说,是在该答案中共享的此链接,并希望将其包含在未来任何困惑的人中。我还更新了标题以更具体地解决问题。

所以基本上,获得所有功能的唯一真正的方法是创建一个临时文件,然后打开该文件,自动重定向到带有片段的正确文件,然后删除它。基本代码如下:

public static void openWebPage(String url) {
    String tmpPath = "path/to/.tmp/temp.html";
    File tempFile = File(tmpPath);
    if (!tempFile.exists()) {
        tempFile.mkdirs();
    } else {
        tempFile.delete();
    }
    tempFile.createNewFile();
    FileWriter tempFileWriter = FileWriter(tmpPath);
    tempFileWriter.write("<html><meta http-equiv=Refresh content=\"0; url=$url\"><body></body></html>");
    tempFileWriter.close();
    Main.getStaticHostServices().showDocument(tmpPath);
}
Run Code Online (Sandbox Code Playgroud)

Sai*_*dem 5

当你检查 HostServices 的源代码时,它实际上只是一个简单的 java 代码Runtime.exec,使用类似这样的代码(对于 Windows):

Runtime.getRuntime().exec(new String[] {
                        "rundll32",
                        "url.dll,FileProtocolHandler",
                        uri
                    });
Run Code Online (Sandbox Code Playgroud)

很明显,JavaFX 在这里没有任何作用。

因此,当尝试使用纯 Java 寻找替代方法时:

Desktop desktop = Desktop.getDesktop();
try {
    desktop.browse(new URI(url));
} catch (IOException ex) {
    throw new RuntimeException(ex);
} catch (URISyntaxException ex) {
    throw new RuntimeException(ex);
}
Run Code Online (Sandbox Code Playgroud)

这在打开文件(没有 id)时效果很好。但是当附加 id 时,它会显示以下错误::

Caused by: java.io.IOException: Failed to open <your filepath>. Error message: The system cannot find the file specified.

    at java.desktop/sun.awt.windows.WDesktopPeer.ShellExecute(WDesktopPeer.java:115)
    at java.desktop/sun.awt.windows.WDesktopPeer.browse(WDesktopPeer.java:101)
    at java.desktop/java.awt.Desktop.browse(Desktop.java:533)
Run Code Online (Sandbox Code Playgroud)

从上面的异常可以很明显地看出,执行一直进行到本机代码并返回错误消息。这反过来得出结论,API 或本机代码或执行(或无论它是什么)正在寻找#其中包含的文件路径。由于找不到,因此会引发错误。

所以我得出的结论是,目前不支持使用标准 java API 从本地文件打开 html 片段。

@其他,如果我的分析有误,请随时纠正我:)

更新1:

经过此链接file:///后,如果我们使用 url.dll 和 FileProtocolHandler,看起来我们需要在路径前面添加前缀。

因此将代码更改为下面实际上打开了浏览器。

String url="file:///C:/folder/test.html#section";
getHostServices().showDocument(uri);
Run Code Online (Sandbox Code Playgroud)

但不幸的是,对特定部分的关注仍然不起作用。至少我会认为这是一次胜利,而不是什么也没表现出来;)

更新2:

好的,看起来我对更新 1 中的行为有所了解。请参阅这些链接link1link2

经过与 Microsoft 的 MSDN 团队反复讨论后,他们审查了 ShellExecute() 调用的源代码,并确定,是的,当在 ShellExecute() 中处理基于 File:/// 的 URL 时,ShellExecute() 调用将在启动默认浏览器并发送 HTML 页面以打开之前,删除 # 以及在 # 之后找到的任何数据。MS 的立场是,他们故意这样做是为了防止注入到该函数中。