2010-03-08 99 views
0

我有一個雅加達下議院HttpClient的問題。 在我自己寫的HttpServer得到真正的請求之前,有一個請求是完全空的。這是第一個問題。 第一個問題解決了。這是由不必要的URLConnection引起的! 第二個問題是,有時請求數據中的http請求的第三或第四行之後結束: 爲什麼我會從Jakarta Commons HttpClient獲取空請求?

POST/HTTP/1.1 
User-Agent: Jakarta Commons-HttpClient/3.1 
Host: 127.0.0.1:4232 

對於調試我使用的軸TCPMonitor中。在那裏,每件事情都很好,但卻是空的要求。

如何處理我流:

StringBuffer requestBuffer = new StringBuffer(); 

InputStreamReader is = new InputStreamReader(socket.getInputStream(), "UTF-8"); 

int byteIn = -1; 
do { 
    byteIn = is.read(); 
    if (byteIn > 0) { 
     requestBuffer.append((char) byteIn); 
    } 
} while (byteIn != -1 && is.ready()); 

String requestData = requestBuffer.toString(); 

發現處理流的新途徑。我讀取所有標題參數並使用'content-length'來讀取發佈數據。

InputStream is = mySocket.getInputStream(); 
if (is == null) { 
    return; 
} 
BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8")); 

// Read the request line 
// ... 
// ... 

// Parse the header 
Properties header = new Properties(); 
if (st.hasMoreTokens()) { 
    String line = in.readLine(); 
    while (line != null && line.trim().length() > 0) { 
     int p = line.indexOf(':'); 
     header.put(line.substring(0, p).trim().toLowerCase(), line.substring(p + 1).trim()); 
     line = in.readLine(); 
    } 
} 

// If the method is POST, there may be parameters 
// in data section, too, read it: 
String postLine = ""; 
if (method.equalsIgnoreCase("POST")) { 
    long size = 0x7FFFFFFFFFFFFFFFl; 
    String contentLength = header.getProperty("content-length"); 
    if (contentLength != null) { 
     try { 
      size = Integer.parseInt(contentLength); 
     } catch (NumberFormatException ex) { 
     } 
    } 
    postLine = ""; 
    char buf[] = new char[512]; 
    int read = in.read(buf); 
    while (read >= 0 && size > 0 && !postLine.endsWith("\r\n")) { 
     size -= read; 
     postLine += String.valueOf(buf, 0, read); 
     if (size > 0) { 
      read = in.read(buf); 
     } 
    } 
    postLine = postLine.trim(); 
    decodeParms(postLine, parms); 
} 

如何發送請求:

client.getParams().setSoTimeout(30000); 

method = new PostMethod(url.getPath()); 
method.getParams().setContentCharset("utf-8"); 
method.setRequestHeader("Content-Type", "application/xml; charset=utf-8"); 
method.addRequestHeader("Connection", "close"); 
method.setFollowRedirects(false); 

byte[] requestXml = getRequestXml(); 

method.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(requestXml))); 

client.executeMethod(method); 

int statusCode = method.getStatusCode(); 

有有人對你的想法如何解決這些問題的問題?

亞歷

回答

1

這可能與您的while循環中的第二個條件有關,isReady()方法可能會在下一次讀取可能會阻塞時返回false - 但您並不在意它是否阻塞,所以我們可以簡單地刪除它(你可以在這裏閱讀更多:http://java.sun.com/j2se/1.5.0/docs/api/java/io/InputStreamReader.html#ready%28%29)。嘗試改變爲:

byte[] buf = new byte[500]; 
while((is.read(buf))>-1){ 
    requestBuffer.append(new String(buf).trim()); 
    buf = new byte[500]; 
} 

現在你應該得到整個請求。

+0

當我刪除is.ready()時,閱讀時間太長。大約需要20秒才能回覆。 – alexvetter 2010-03-08 13:26:01

+0

當您說'響應回來'時,是否需要20秒才能將請求xml讀入請求緩衝區? – simonlord 2010-03-08 14:06:47

+0

整個請求在讀取請求xml併發送響應時需要約20秒的時間。 – alexvetter 2010-03-08 15:08:19

1

我不知道關於第一個問題,但我認爲你的第二個問題是由於這樣的:

} while (byteIn != -1 && is.ready()); 

如果發件人是不夠快發送數據,接收器可能會在下一個數據包發送之前調用is.ready()。這將導致is.ready()返回false這將導致循環停止。

最小的解決辦法是該行更改爲:

} while (byteIn != -1); 

編輯

不過說真的,你需要重寫沿@ simonlord的答案的線條方法。一次讀取一個字節的非緩衝流是一個非常糟糕的主意。你最終會爲每個read調用做一個系統調用,這是非常低效的。

EDIT 2

,取消is.ready()造成延誤的原因是因爲你沒有支付適當的關注HTTP協議。問題在於HttpClient代碼將TCP連接的請求端打開以允許重新使用連接。簡單的(但是次優的)解決方案應該是配置HttpClient來關閉連接的請求端。你的代碼會馬上看到EOF。你實際上做的是另一種解決方案。

坦率地說,你甚至不應該是嘗試來實現服務器端HTTP協議,除非你準備深入理解整個HTTP規範並忠實地實現它。有可能現有的實現將比任何可以拼湊在一起的任何東西都更快,更可靠。實現規範的一個子集的問題在於,您的服務器可能需要與真正的瀏覽器進行通信,該瀏覽器使用了您尚未執行/測試的部分規範。

+0

當我刪除is.ready()時,閱讀時間過長。大約需要20秒才能回覆。 – alexvetter 2010-03-08 13:20:37

相關問題