說明
我也有這個問題,並通過提供我自己的實現的sun.net.www.protocol.http.HttpURLConnection
,我用它來處理任何AJAX請求解決它。我的課程便利地稱爲AjaxHttpURLConnection
,它掛接到getInputStream()
函數,但不返回其原始輸入流。相反,我將PipedInputStream
的實例返回給WebEngine
。然後我讀取來自原始輸入流的所有數據,並將其傳遞給我的管道流。 這樣,我獲得了2個好處:
- 我知道什麼時候收到最後一個字節,因此AJAX請求已被完全處理。
- 我甚至可以抓取所有傳入的數據,並已經使用它(如果我想)。
例
首先,你將不得不告訴Java使用而不是默認的你的URLConnection實現。爲此,您必須提供您自己的URLStreamHandlerFactory
版本。您可以在此處找到許多線索(例如this one)或通過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);
}
}
其次,我們要拿出我們自己的Handler
告訴何時使用哪種類型的URLConnection
程序。
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
,因此其瀏覽器已經完成加載。
- 您可能已經注意到,我只通過http連接進行身份驗證。我還沒有測試我的方法可以轉移到https等多遠(不是這裏的專家:O)。
- 正如你所看到的,我知道何時使用我的
AjaxHttpURLConnection
的唯一方法是當相應的url包含ajax=1
。就我而言,這足夠了。因爲我對html和http不太瞭解,但是我不知道WebEngine
是否可以用任何不同的方式發出AJAX請求(例如頭字段?)。如果有疑問,你可以簡單地總是返回一個修改後的url連接的實例,但這當然意味着一些開銷。
- 正如開頭所述,如果您希望這樣做,您可以立即使用從輸入流中檢索到的數據。您可以獲取您的
WebEngine
以類似方式發送的請求數據。只需包裝getOutputStream()
函數,並放置另一箇中間流來抓取正在發送的任何內容,然後將其傳遞到原始輸出流。
我面臨同樣的問題。你能找到解決方案嗎? – wib
@wib:不幸的是,我嘗試了一些黑客,但是問題在於Web引擎構建在庫中的更深層次。最適合我的黑客只是暫停轉換,讓javafx線程「睡眠」一段時間,並希望js在那時完成... – Warkst
我想過這樣做,但它嚴重依賴於可靠的Internet連接。看起來這是目前最好的解決方案 – wib