我正在用JavaFX开发一个数据挖掘应用程序,它依赖于WebView(因此也依赖于WebEngine)。挖掘分两步进行:首先,用户使用UI导航到WebView中的一个网站,以配置可以在哪里搜索感兴趣的数据。其次,使用定期运行的后台任务,WebEngine加载相同的文档,并尝试从加载的文档中提取数据。
这种方法在大多数情况下都能很好地工作,但是最近我遇到了一些使用AJAX呈现内容的页面的麻烦。为了检查WebEngine是否加载了文档,我监听LoadWorker
的StateProperty
。如果状态转换为succesfull,我知道文档已加载(以及可能运行在document.ready()或等效文件上的任何javascript)。这是因为javascript是在JavaFX线程上执行的,如果我没有弄错的话(来源:https://blogs.oracle.com/JavaFX/entry/communication_between_javascript_and_javafx)。但是,如果启动了AJAX调用,javascript执行结束,引擎让我知道文档已经准备好了,尽管显然还没有准备好,因为内容仍然可能由于未完成的AJAX调用而发生变化。
有没有办法解决这个问题,注入一个钩子,以便在AJAX调用完成时通知我?我尝试在$.ajaxsetup()
中安装一个默认的完整处理程序,但这是相当不可靠的,因为如果ajax调用覆盖完整处理程序,则不会调用默认处理程序。另外,我只能在文档首次加载之后(到那时,一些AJAX调用可能已经在运行)才可以注入。我已经用一个upcall测试了这个注入,它可以很好地适用于根据命令(在注入默认处理程序之后)启动的AJAX调用,这些调用不提供自己的完整处理程序。
我正在寻找两个东西:首先:一种挂接到AJAX调用的完成处理程序的通用方法,其次:一种等待WebEngine完成所有AJAX调用并在之后通知我的方法。
我也遇到过这个问题,并通过提供我自己的sun.net.www.protocol.http.httpurlConnection
实现来解决这个问题,我使用它来处理任何AJAX请求。我的类被方便地称为AjaxHttpurlConnection
,它挂钩到getInputStream()
函数中,但不返回它的原始输入流。相反,我将PipedInputStream
的一个实例返回到WebEngine
。然后读取来自原始输入流的所有数据,并将其传递到管道流。这样,我得到了2个好处:
首先,您必须告诉Java使用您的URLConnection实现,而不是默认的实现。为此,必须为其提供自己版本的URLStreamHandlerFactory
。你可以在SO(例如这一个)或通过Google找到许多关于这个主题的线程。为了设置工厂实例,请在main
方法的早期位置放置以下内容。这就是我的样子。
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
public class MyApplication extends Application {
// ...
public static void main(String[] args) {
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("http".equals(protocol)) {
return new MyUrlConnectionHandler();
}
return null; // Let the default handlers deal with whatever comes here (e.g. https, jar, ...)
}
});
launch(args);
}
}
import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import sun.net.www.protocol.http.Handler;
import sun.net.www.protocol.http.HttpURLConnection;
public class MyUrlConnectionHandler extends Handler {
@Override
protected URLConnection openConnection(URL url, Proxy proxy) throws IOException {
if (url.toString().contains("ajax=1")) {
return new AjaxHttpURLConnection(url, proxy, this);
}
// Return a default HttpURLConnection instance.
return new HttpURLConnection(url, proxy);
}
}
最后但并非最不重要的是,这里有AjaxHttpurlConnection
。
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.Proxy;
import java.net.URL;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.io.IOUtils;
import sun.net.www.protocol.http.Handler;
import sun.net.www.protocol.http.HttpURLConnection;
public class AjaxHttpURLConnection extends HttpURLConnection {
private PipedInputStream pipedIn;
private ReentrantLock lock;
protected AjaxHttpURLConnection(URL url, Proxy proxy, Handler handler) {
super(url, proxy, handler);
this.pipedIn = null;
this.lock = new ReentrantLock(true);
}
@Override
public InputStream getInputStream() throws IOException {
lock.lock();
try {
// Do we have to set up our own input stream?
if (pipedIn == null) {
PipedOutputStream pipedOut = new PipedOutputStream();
pipedIn = new PipedInputStream(pipedOut);
InputStream in = super.getInputStream();
/*
* Careful here! for some reason, the getInputStream method seems
* to be calling itself (no idea why). Therefore, if we haven't set
* pipedIn before calling super.getInputStream(), we will run into
* a loop or into EOFExceptions!
*/
// TODO: timeout?
new Thread(new Runnable() {
public void run() {
try {
// Pass the original data on to the browser.
byte[] data = IOUtils.toByteArray(in);
pipedOut.write(data);
pipedOut.flush();
pipedOut.close();
// Do something with the data? Decompress it if it was
// gzipped, for example.
// Signal that the browser has finished.
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
} finally {
lock.unlock();
}
return pipedIn;
}
}
WebEngine
对象,则可能很难判断哪个对象实际打开了URLConnection
以及哪个浏览器已完成加载。AjaxHttpurlConnection
的唯一方法是当对应的url包含Ajax=1
时。对我来说,这就足够了。但是,由于我不太擅长html和http,所以我不知道webengine
是否可以以任何不同的方式发出AJAX请求(例如,头字段?)。如果有疑问,您可以返回修改后的url连接的实例,但这当然意味着一些开销。WebEngine
发送的请求数据。只需包装getOutputStream()
函数,并放置另一个中间流来获取正在发送的内容,然后将其传递给原始输出流。问题内容: 我正在使用Selenium 2 WebDriver来测试使用AJAX的UI。 有没有一种方法可以使驱动程序稍稍等待Ajax请求将完成。 基本上我有这个: 问题答案:
问题内容: 嗨,我的脚本中有2个Ajax调用,我需要它们运行asnyc以节省时间,但是我需要第二个才能等待第一个完成。 有什么想法吗?谢谢 问题答案: 如果使用jQuery 1.5+,则可以使用jQuery 完成。诸如此类的东西(缩短了ajax的简洁性,只需像上面那样传递对象) 您不知道它们将以什么顺序返回,因此,如果您手动滚动此请求,则需要检查另一个请求的状态并等待它返回。
问题内容: 我需要等到我所有的ajax函数都完成后,再继续执行。 我的特殊情况是,在提交表单之前,我需要翻译表单中的某些字段。我通过ajax调用将其转换为外部站点。根据表单中的某些值,我需要进行更多或更少的翻译。完成所有翻译后(如果有),我必须使用ajax验证表单,如果表单有效,则提交。 这是我的方法: 首先,我有一个函数发送ajax调用并对接收到的数据进行处理: 然后,当要提交表单时,我将执行以
我通读了Dart/flatter中的Async/Await/then,试图理解为什么aysnc函数中的Await不会等到完成后再继续。在我的UI中,有一个按钮调用一个异步方法来返回一个位置,该位置总是返回null,并且不等待函数完成。 该函数将调用推送到一个新的UI页面,该页面选择一个位置,并应返回一个结果。如何使该函数等待结果?我不是在使用异步吗?
问题内容: 为什么每当我将ajax放入for循环中时,它都无法很好地同步? 例如,我的代码是: 为什么它先调用Ajax查询?是否有可能让ajax查询在继续之前完成?因为它在完成填充之前就清除了数组。:/ 问题答案: 首先,您确实需要了解Ajax调用是如何异步的(这就是Ajax中的“ A”所代表的意思)。这意味着调用仅启动ajax调用(它将请求发送到服务器),其余代码愉快地继续运行。有时,在其余代码
问题内容: 我有以下 我有一个运行一些ajax的函数,然后根据ajax是否成功返回true或false。我从代码的多个位置调用了这个ajax函数。 因为该函数在ajax完成之前结束,所以它总是返回false。如何避免这种情况? 我读到一些建议我在函数中执行的操作,然后将和函数移至我的和函数。但是,在我的方法中,我进行了大量的计算。很多代码。因此,问题在于,如果我将功能移至其他功能,那么我将复制一堆