2010-08-06 129 views
2

我正在寫一個HTTP代理,它是測試/驗證 系統的一部分。代理過濾來自客戶端設備 的所有請求,並將它們引導至各種被測系統。servlet中的問題讀取請求體

該代理被實現爲一個servlet,其中每個請求被轉發 到目標系統,它同時處理GET和POST。有時,目標系統的響應被改變以適應各種測試條件,但這不是問題的一部分。

轉發請求時,除了作爲實際HTTP傳輸的一部分的那些 (例如Content-Length和 連接標頭)之外,將複製所有標頭。

如果請求是一個HTTP POST,那麼請求的實體主體也會被轉發到 ,這裏有時它不起作用。

的代碼從servlet請求讀取實體正文如下:

URL url = new URL(targetURL); 
HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
String method = request.getMethod(); 

java.util.Enumeration headers = request.getHeaderNames(); 
while(headers.hasMoreElements()) { 

    String headerName = (String)headers.nextElement(); 
    String headerValue = request.getHeader(headerName); 

    if (...) { // do various adaptive stuff based on header 

    } 

    conn.setRequestProperty(headerName, headerValue); 
} 

//這裏失敗

char postBody[] = new char[1024]; 
int len; 

if(method.equals("POST")) { 
    logger.debug("guiProxy, handle post, read request body"); 
    conn.setDoOutput(true); 

    BufferedReader br = request.getReader(); 
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream())); 

    do { 
     logger.debug("Read request into buffer of size: " + postBody.length); 

     len = br.read(postBody, 0, postBody.length); 
     logger.debug("guiProxy, send request body, got " + len + " bytes from request"); 

     if(len != -1) { 
      bw.write(postBody, 0, len); 
     } 
    } while(len != -1); 
    bw.close(); 
} 

的一部分,所以什麼happends是第一次POST -1 字符是從請求閱讀器讀取的,wireshark trace顯示 包含URL編碼後參數的實體正文 並且它位於一個TCP段中,因此存在n個o網絡相關 的差異。

第二次,br.read成功返回 POST請求實體主體中的232個字節,並且每個即將發出的請求也都能正常工作。

第一個和即將發佈的POST請求之間的唯一區別是 ,第一個不存在cookie,但在第二個 中存在映射到JSESSION的cookie。

它可能是實體主體不可用的副作用,因爲在servlet容器中的 請求處理已經讀取POST 參數,但它爲什麼會對即將發生的請求起作用。

相信溶液當然是忽略在含有URL編碼數據 POST請求實體主體和代替使用的getParameter從servlet請求獲取所有參數 和重新插入 詮釋傳出請求。

雖然這是棘手的,因爲POST請求可能包含GET 參數,而不是現在我們的應用程序中,但正確執行它 是一些工作。

所以我的問題基本上是:爲什麼一些讀者對 request.getReader()返回-1閱讀時和實體主體是 出現在請求時,如果實體身體不適用於 閱讀,然後getReader應該拋出非法狀態異常。 I 也嘗試使用getInputStream()與InputStream結果相同的 。

所有這些都在apache-tomcat-6.0.18上測試過。

回答

5

所以我的問題基本上是:爲什麼閱讀時request.getReader()返回-1。

它會返回-1,當沒有任何物體或者它有時已經讀取。你不能讀它兩次。確保請求/響應鏈中沒有任何內容讀取它。

並且請求中存在實體主體,如果實體主體不可讀取,則getReader應拋出非法狀態異常。

它只會拋出,當你已經請求getInputStream()之前,而不是當它不可用時。

我也嘗試過使用getInputStream()的InputStream和相同的結果。

畢竟,我寧願流不是字符字節,因爲你再不需要把字符編碼考慮(你現在還沒有做遠,這可能會在以後會導致問題讓這一切工作)。

+0

似乎cookie的存在阻止了servlet容器讀取POST主體。這解釋了爲什麼後面的帖子請求能夠工作,因爲當cookie被設置時它就起作用了。 現在,我的解決方案,雖然有點尷尬,但是手動將所有POST參數傳遞給代理請求實體主體,但它現在可行。我相信構建代理的正確方法是使用servlet過濾器,然後可以控制整個請求。 – Ernelli 2010-08-09 14:01:51

1

看來,所有的操作,即讀取請求(如request.getHeader())之前移動

BufferedReader br = request.getReader() 

,工作對我來說很好。