2013-07-08 70 views
4

我正在嘗試爲使用webview訪問單個網站的JavaFX應用程序編寫自己的協議處理程序。什麼到目前爲止,我已經做了自定義JavaFX WebView協議處理程序

我定製URLStreamHandlerFactory

public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory { 

    public URLStreamHandler createURLStreamHandler(String protocol) { 
     System.out.println("Protocol: " + protocol); 
     if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) { 
      return new MyURLStreamHandler(); 
     } else { 
      return new URLStreamHandler() { 
       @Override 
       protected URLConnection openConnection(URL u) throws IOException { 
        return new URLConnection(u) { 
         @Override 
         public void connect() throws IOException { 
         } 
        }; 
       } 
      }; 
     } 
    } 
} 

我定製的URLStreamHandler

public class MyURLStreamHandler extends java.net.URLStreamHandler{ 

    protected HttpURLConnection openConnection(URL u){ 
     MyURLConnection q = new MyURLConnection(u); 
     return q; 
    }  
} 

我定製HttpURLConnection的

public class MyURLConnection extends HttpURLConnection { 

    static int defaultPort = 443; 
    InputStream in; 
    OutputStream out; 
    Socket s; 

    publicMyURLConnection(URL url) { 
     super(url); 
     try { 
      setRequestMethod("POST"); 
     } catch (ProtocolException ex) { 
      ex.printStackTrace(); 
     } 
    } 

    public void setRequestProperty(String name, String value){ 
     super.setRequestProperty(name, value); 
     System.out.println("Namee: " + name); 
     System.out.println("Value: " + value); 
    } 

    public String getRequestProperty(String name){ 
     System.out.println("GET REQUEST: "); 
     return super.getRequestProperty(name); 
    } 

    public OutputStream getOutputStream() throws IOException { 
     OutputStream os = super.getOutputStream(); 
     System.out.println("Output: " + os); 
     return os; 
    } 

    public InputStream getInputStream() throws IOException { 
     InputStream is = super.getInputStream(); 
     System.out.println("INout stream: " + is); 
     return is; 
    } 

    @Override 
    public void connect() throws IOException { 
    } 

    @Override 
    public void disconnect() { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    @Override 
    public boolean usingProxy() { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

當我運行的應用程序,我得到以下錯誤althouhg它似乎設置了一些標頭

Jul 08, 2013 11:09:04 AM com.sun.webpane.webkit.network.URLLoader doRun 
WARNING: Unexpected error 
java.net.UnknownServiceException: protocol doesn't support input 
at java.net.URLConnection.getInputStream(URLConnection.java:839) 
at qmed.QMedURLConnection.getInputStream(MyURLConnection.java:67) 
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468) 
at com.sun.webpane.webkit.network.URLLoader.receiveResponse(URLLoader.java:383) 
at com.sun.webpane.webkit.network.URLLoader.doRun(URLLoader.java:142) 
at com.sun.webpane.webkit.network.URLLoader.access$000(URLLoader.java:44) 
at com.sun.webpane.webkit.network.URLLoader$1.run(URLLoader.java:106) 
at com.sun.webpane.webkit.network.URLLoader$1.run(URLLoader.java:103) 
at java.security.AccessController.doPrivileged(Native Method) 
at com.sun.webpane.webkit.network.URLLoader.run(URLLoader.java:103) 
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) 
at java.util.concurrent.FutureTask.run(FutureTask.java:166) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
at java.lang.Thread.run(Thread.java:724) 

我想要做的就是獲取給定請求的響應並讀取它的二進制數據。我希望協議的行爲與缺省協議的行爲完全相同,並只檢查給定響應的二進制數據。我究竟做錯了什麼?

該應用程序正在做URLConnections的所有短路。當協議是http或https時,使用HTTPURLConnection作爲我的自定義URLConnection類並且在使用其他協議時像我在MyURLStreamHandlerFactory中使用時啓動默認的URLStreamHandler,是正確的嗎?我應該只擴展MYURLConnection中的默認URLConnection類來處理所有協議相同嗎?

任何幫助將非常感激,因爲這是一個項目威脅的問題

謝謝

回答

3

這可能是你缺少的是一個setDoInput(true)或覆蓋getDoInput()並返回true(這就是我所做的那樣) 。

如果不幫看看我工作的解決方案:

MyURLStreamHandlerFactory:

import java.net.URLStreamHandler; 
import java.net.URLStreamHandlerFactory; 

public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory 
{ 

    public URLStreamHandler createURLStreamHandler(String protocol) 
    { 
     if (protocol.equals("myapp")) 
     { 
      return new MyURLHandler(); 
     } 
     return null; 
    } 

} 

註冊廠:

URL.setURLStreamHandlerFactory(new MyURLStreamHandlerFactory()); 

MyURLHandler:

import java.io.IOException; 
import java.net.URL; 
import java.net.URLConnection; 
import java.net.URLStreamHandler; 

public class MyURLHandler extends URLStreamHandler 
{ 

    @Override 
    protected URLConnection openConnection(URL url) throws IOException 
    { 
     return new MyURLConnection(url); 
    } 

} 

MyURLConnection:

import java.io.*; 
import java.net.SocketTimeoutException; 
import java.net.URL; 
import java.net.URLConnection; 

/** 
* Register a protocol handler for URLs like this: <code>myapp:///pics/sland.gif</code><br> 
*/ 
public class MyURLConnection extends URLConnection 
{ 

    private byte[] data; 

    @Override 
    public void connect() throws IOException 
    { 
     if (connected) 
     { 
      return; 
     } 
     loadImage(); 
     connected = true; 
    } 

    public String getHeaderField(String name) 
    { 
     if ("Content-Type".equalsIgnoreCase(name)) 
     { 
      return getContentType(); 
     } 
     else if ("Content-Length".equalsIgnoreCase(name)) 
     { 
      return "" + getContentLength(); 
     } 
     return null; 
    } 

    public String getContentType() 
    { 
     String fileName = getURL().getFile(); 
     String ext = fileName.substring(fileName.lastIndexOf('.')); 
     return "image/" + ext; // TODO: switch based on file-type 
    } 

    public int getContentLength() 
    { 
     return data.length; 
    } 

    public long getContentLengthLong() 
    { 
     return data.length; 
    } 

    public boolean getDoInput() 
    { 
     return true; 
    } 

    public InputStream getInputStream() throws IOException 
    { 
     connect(); 
     return new ByteArrayInputStream(data); 
    } 

    private void loadImage() throws IOException 
    { 
     if (data != null) 
     { 
      return; 
     } 
     try 
     { 
      int timeout = this.getConnectTimeout(); 
      long start = System.currentTimeMillis(); 
      URL url = getURL(); 

      String imgPath = url.toExternalForm(); 
      imgPath = imgPath.startsWith("myapp://") ? imgPath.substring("myapp://".length()) : imgPath.substring("myapp:".length()); // attention: triple '/' is reduced to a single '/' 

      // this is my own asynchronous image implementation 
      // instead of this part (including the following loop) you could do your own (synchronous) loading logic 
      MyImage img = MyApp.getImage(imgPath); 
      do 
      { 
       if (img.isFailed()) 
       { 
        throw new IOException("Could not load image: " + getURL()); 
       } 
       else if (!img.hasData()) 
       { 
        long now = System.currentTimeMillis(); 
        if (now - start > timeout) 
        { 
         throw new SocketTimeoutException(); 
        } 
        Thread.sleep(100); 
       } 
      } while (!img.hasData()); 
      data = img.getData(); 
     } 
     catch (InterruptedException e) 
     { 
      e.printStackTrace(); 
     } 
    } 

    public OutputStream getOutputStream() throws IOException 
    { 
     // this might be unnecessary - the whole method can probably be omitted for our purposes 
     return new ByteArrayOutputStream(); 
    } 

    public java.security.Permission getPermission() throws IOException 
    { 
     return null; // we need no permissions to access this URL 
    } 

} 

MyURLConnection某些部分可能沒有必要爲它工作,但這樣的工作對我來說。

使用JavaFX中的WebView:

<img src="myapp:///pics/image.png"/> 

注意有關權限:

我用了一個小程序所有權限我與上面的代碼測試。

沙箱-Applet這將不起作用,因爲setFactory權限丟失。

+0

很好的答案。到目前爲止,我發現它離我的需求最近。但我想要的是捕獲所有協議。 HTTP,HTTPS,file://就像我們可以在開發者控制檯中看到所有請求一樣。 –

+0

你想用這個做什麼?也許一個網絡嗅探器/分析器工具將做你想做的。 –

+0

另一件可能有用的事情是使用FirebugLite:'' - 將此代碼嵌入您的WebView頁面,您可以在WebView中調試頁面。不幸的是,FBLite沒有網絡標籤。 –

-1

這與問題沒有直接關係,但可能會使問題本身過時。

使用Java SE 6 Update 10 Java Applets支持訪問正確設置的任何域和端口上的資源帶有crossdomain.xml

由於您可以訪問您需要的所有資源,因此註冊您自己的協議的原因可能會過時。

另一個想法是:如果你想創造一種網絡嗅探器,爲什麼不直接使用專爲此類任務的網絡嗅探器/分析儀程序?

-2

通過激活記錄和Java控制面板的Java控制檯中跟蹤將打印所有的嘗試和執行網絡調用包括來自web視圖。

你可以看到所有HTTP & HTTPS調用及其返回代碼+ cookie數據。 您可能還會看到其他協議連接,但可能不會發送通過它們發送的任何數據。

這適用於瀏覽器中的小程序。 如果你需要在不同的環境下使用,也許有辦法通過傳遞命令行參數來激活相同的選項。