2011-12-12 56 views
0

Intranet站點有一個搜索表單,它使用AJAX在不同的域上調用一個用於搜索建議的servlet。爲什麼這個HTTP servlet行爲不一致?

這適用於Internet Explorer,Intranet域是「受信任的站點」,爲受信任的站點啓用了跨域請求,但在Firefox中不起作用。

我試圖通過在Intranet服務器上創建一個servlet來解決這個問題,所以在同一個域上有一個到我的servlet的JS調用,然後我的servlet在另一個域上調用建議servlet。跨域調用是服務器端的,所以它應該工作,不管瀏覽器設置如何。

AJAX調用和我的servlet對另一個servlet的調用都使用帶有URL參數和空請求內容的HTTP POST請求。

我堅持POST請求的原因是JS代碼都在搜索服務器上的文件中,我不能修改,並且該代碼使用POST請求。

我已經嘗試用GET請求調用客戶的現有建議servlet,它會產生404錯誤。

問題是結果不一致。

我用System.out.println調用來顯示服務器日誌上結果的完整URL和大小。

輸出第一次似乎根據調用瀏覽器和/或網站而改變,但現在似乎甚至在同一瀏覽器的會話之間改變。

E.g.在搜索框中輸入「G」,我使用的是Firefox從發展環境,第一幾次嘗試這樣的輸出:

Search suggestion URL: http://searchdev.companyname.com.au/suggest?q=g&max=10&site=All&client=ie&access=p&format=rich 
Search suggestion result length: 64 
在測試環境中產生與Firefox

初步嘗試(不同的內網服務器,但相同的搜索服務器)相同搜索網址的結果長度爲0。
使用Internet Explorer進行的初始嘗試在兩種環境中都會產生結果長度爲0的結果。

然後我試着搜索不同的字母,發現「t」在IE中沒有產生結果。

關閉瀏覽器並留下一段時間後,我再次嘗試並得到不同的結果。

E.g.使用Firefox並在開發環境中嘗試「g」現在不會產生以前生成結果的結果。

不一致使我認爲我的servlet代碼出現了問題,如下所示。什麼可能導致這個問題?

我認爲搜索建議是由Google Search Appliance提供的,搜索服務器上的JS文件似乎都來自Google。

實際的AJAX調用是這條線在一個文件中:

XH_XmlHttpPOST(xmlhttp, url, '', handler); 

的XH_XmlHttpPOST功能是在另一個文件如下:

function XH_XmlHttpPOST(xmlHttp, url, data, handler) { 
    xmlHttp.open("POST", url, true); 
    xmlHttp.onreadystatechange = handler; 
    xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
    xmlHttp.setRequestHeader("Content-Length", 
     /** @type {string} */ (data.length)); 
    XH_XmlHttpSend(xmlHttp, data); 
} 

這裏是我的servlet代碼:

package com.companyname.theme; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.PrintWriter; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.Properties; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

public class suggest extends HttpServlet { 
    Properties props=null; 

    @Override 
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException { 

     String result = ""; 
     String args = req.getQueryString(); 
     String baseURL = props.getProperty("searchFormBaseURL"); 
     String urlStr = baseURL + "/suggest?" + args; 
     System.out.println("Search suggestion URL: " + urlStr); 

     try { 
      int avail, rCount; 
      int totalCount = 0; 
      byte[] ba = null; 
      byte[] bCopy; 
      URL url = new URL(urlStr); 
      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
      conn.setRequestMethod("POST"); 
      conn.setDoOutput(true); 
      OutputStream os = conn.getOutputStream(); 
      os.write("".getBytes()); 
      os.close(); 
      InputStream is = conn.getInputStream(); 
      while ((avail = is.available()) > 0) { 
       if (ba == null) ba = new byte[avail]; 
       else if (totalCount + avail > ba.length) { 
        // Resize ba if there's more data available. 
        bCopy = new byte[totalCount + avail]; 
        System.arraycopy(ba, 0, bCopy, 0, totalCount); 
        ba = bCopy; 
        bCopy = null; 
       } 
       rCount = is.read(ba, totalCount, avail); 
       if (rCount < 0) break; 
       totalCount += rCount; 
      } 
      is.close(); 
      conn.disconnect(); 
      result = (ba == null ? "" : new String(ba)); 
      System.out.println("Search suggestion result length: " + Integer.toString(result.length())); 
     } catch(MalformedURLException e) { 
      e.printStackTrace(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
     PrintWriter pw = resp.getWriter(); 
     pw.print(result); 
    } 

    @Override 
    public void init() throws ServletException { 
     super.init(); 
     InputStream stream = this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties"); 
     props = new Properties(); 
     try { 
      props.load(stream); 
      stream.close(); 
     } catch (Exception e) { 
      // TODO: handle exception 
     } 
    } 
    } 
+0

你甚至沒有注意到你的文章中的所有內容都顯示了嗎?我的意思是,我同意,要經歷很多事情;您可能需要稍微編輯它。 –

+0

我張貼後立即看着它,它似乎都在那裏。什麼是錯過的,你需要改變什麼? –

+0

一半的servlet。我使用了SO所使用的標記(加上一些freakin'空格,所以代碼清晰可見),並略微去除了散文。 –

回答

1

解決方法:不要依賴InputStream.available()

這個方法的JavaDoc的說,它總是返回0
HttpURLConnection.getInputStream()的實際返回HttpInputStream,其中available()似乎工作,但顯然有時會返回0,當有更多的數據。

我改變了我的閱讀循環,根本不使用available(),現在它始終如一地返回預期結果。
正在工作的servlet位於下方。

package com.integral.ie.theme; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.PrintWriter; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.Properties; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

public class suggest extends HttpServlet implements 
javax.servlet.Servlet { 
    Properties props=null; 

    @Override 
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException { 
     //super.doPost(req, resp); 
     final int maxRead=200; 

     String result=""; 
     String args=req.getQueryString(); 
     String baseURL=props.getProperty("searchFormBaseURL"); 
     String urlStr=baseURL+"/suggest?"+args; 
     //System.out.println("Search suggestion URL: "+urlStr); 
     try { 
      int rCount=0; 
      int totalCount=0; 
      int baLen=maxRead; 
      byte[] ba=null; 
      byte[] bCopy; 
      URL url=new URL(urlStr); 
      HttpURLConnection conn=(HttpURLConnection)url.openConnection(); 
      conn.setRequestMethod("POST"); 
      // Setting these properties may be unnecessary - just did it 
      // because the GSA javascript does it. 
      conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
      conn.setRequestProperty("Content-Length","0"); 

      InputStream is=conn.getInputStream(); 
      ba=new byte[baLen]; 
      while (rCount>=0) { 
       try { 
        rCount=is.read(ba,totalCount,baLen-totalCount); 
        if (rCount>0) { 
         totalCount+=rCount; 
         if (totalCount>=baLen) { 
          baLen+=maxRead; 
          bCopy=new byte[baLen]; 
          System.arraycopy(ba,0,bCopy,0,totalCount); 
          ba=bCopy; 
          bCopy=null; 
         } 
        } 
       } catch(IOException e) { 
        // IOException while reading - allow the method to return 
        // anything we've read so far. 
       } 
      } 

      is.close(); 
      conn.disconnect(); 
      result=(totalCount==0?"":new String(ba,0,totalCount)); 

      //System.out.println("Search suggestion result length: " 
      //+Integer.toString(result.length())); 

     } catch(MalformedURLException e) { 
      e.printStackTrace(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
     PrintWriter pw=resp.getWriter(); 
     pw.print(result); 
    } 

    @Override 
    public void init() throws ServletException { 
     super.init(); 
     InputStream stream=this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties"); 
     props=new Properties(); 
     try { 
      props.load(stream); 
      stream.close(); 
     } catch (Exception e) { 
      // TODO: handle exception 
     } 
    } 
}
0

從單元測試開始。 Servlet對於單元測試非常簡單,而HttpUnit已經爲我們工作。

在瀏覽器和println調用中調試Servlet代碼將花費更多時間,長期來看,SO上的人很難消化所有這些信息來幫助您。

此外,請考慮使用JavaScript框架(如JQuery)來處理AJAX調用。在我看來,現在沒有理由直接觸摸xmlHttp對象,因爲框架會爲您隱藏它。

+0

我沒有使用AJAX框架,因爲javascript已經存在於搜索服務器上了 - 如果它有效,不需要重寫。 單元測試 - 通常聽起來像一個好主意,但我從來沒有做過。學習一個小servlet的時間似乎過分了。 –