我正在嘗試使用java HttpURLConnection中的RFC Expect Header,除了一個細節外,它作業得很好。
在發送固定長度模式的正文之間或在塊流模式下的每個塊之間有 5 秒的等待時間
這是客戶端類
public static void main(String[] args)throws Exception
{
HttpURLConnection con=(HttpURLConnection)new URL("http://192.168.1.2:2000/ActionG").openConnection();
//for 100-Continue logic
con.setRequestMethod("POST");
con.setRequestProperty("Expect", "100-Continue");
//responds to 100-continue logic
con.setDoOutput(true);
con.setChunkedStreamingMode(5);
con.getOutputStream().write("Hello".getBytes());
con.getOutputStream().flush();
con.getOutputStream().write("World".getBytes());
con.getOutputStream().flush();
con.getOutputStream().write("123".getBytes());
con.getOutputStream().flush();
//decode response and response body/error if any
System.out.println(con.getResponseCode() "/" con.getResponseMessage());
con.getHeaderFields().forEach((key,values)->
{
System.out.println(key "=" values);
System.out.println("====================");
});
try(InputStream is=con.getInputStream()){System.out.println(new String(is.readAllBytes()));}
catch(Exception ex)
{
ex.printStackTrace(System.err);
InputStream err=con.getErrorStream();
if(err!=null)
{
try(err){System.err.println(new String(is.readAllBytes()));}
catch(Exception ex2){throw ex2;}
}
}
con.disconnect();
}
我正在上傳 3 個塊。在服務器端接收到 5 個資料包
所有標題。回復 100 繼續
3 塊。對于每個塊回應 100 繼續
最后一個塊[長度 0]。回復 200 OK
這是測驗服務器
final class TestServer
{
public static void main(String[] args)throws Exception
{
try(ServerSocket socket=new ServerSocket(2000,0,InetAddress.getLocalHost()))
{
int count=0;
try(Socket client=socket.accept())
{
int length;
byte[] buffer=new byte[5000];
InputStream is=client.getInputStream();
OutputStream os=client.getOutputStream();
while((length=is.read(buffer))!=-1)
{
System.out.println( count);
System.out.println(new String(buffer,0,length));
System.out.println("==========");
if(count<5)
{
os.write("HTTP/1.1 100 Continue\r\n\r\n".getBytes());
os.flush();
}
else
{
os.write("HTTP/1.1 200 Done\r\nContent-Length:0\r\n\r\n".getBytes());
os.flush();
break;
}
}
}
}
}
}
輸出:
1
POST /ActionG HTTP/1.1
Expect: 100-Continue
User-Agent: Java/17.0.2
Host: 192.168.1.2:2000
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
========== //5 seconds later
2
5
Hello
========== //5 seconds later
3
5
World
========== //5 seconds later
//this and the last chunk come seperatly but with no delay
4
3
123
==========
5
0
==========
我檢查了連接物件中的每個超時方法
System.out.println(con.getConnectTimeout());
System.out.println(con.getReadTimeout());
兩者都回傳 0
那么這個 5 秒的延遲是從哪里來的呢?
我在 Windows 10 中使用 jdk 17.0.2
uj5u.com熱心網友回復:
3 塊。對于每個塊回應 100 繼續
這不是如何Expect: 100-Continue作業的。您的服務器代碼對于您嘗試執行的操作是完全錯誤的。事實上,您的服務器代碼對于一般的 HTTP 服務器來說是完全錯誤的。它甚至根本沒有嘗試決議 HTTP 協議。不是 HTTP 標頭,不是 HTTP 塊,什么都沒有。您是否有理由不使用實際的 HTTP 服務器實作,例如 Java 自己的HttpServer?
使用Expect: 100-Continue時,客戶端只需要發送請求頭,然后停止并等待幾秒鐘,看看服務器是否發送100回應:
如果服務器以 回應
100,則客戶端可以通過發送請求正文來完成請求,然后接收最終回應。如果服務器回應的不是
100,則客戶端可以立即使其操作失敗,而根本不發送請求正文。如果沒有收到回應,客戶端可以通過發送請求正文來完成請求并接收最終回應。
整個要點Expect: 100-Continue是客戶端在發送大型請求正文之前請求許可。如果服務器不想要正文(即,標頭描述了不令人滿意的條件等),客戶端不必浪費精力和帶寬來發送將被拒絕的請求正文。
HttpURLConnection具有處理回應的內置支持100,但請參閱如何使用 HttpURLConnection 在 Java 中等待 Expect 100-continue 回應以獲取警告。另請參閱HttpURLConnection 中的 JDK-8012625:HTTP/1.1 “Expect: 100-continue”的錯誤處理。
但是,如圖所示,您的服務器代碼需要大量重寫才能正確處理 HTTP ,更不用說正確處理分塊請求了。
uj5u.com熱心網友回復:
所以感謝@Remy Lebeau 關于如何正確決議這個特殊標題的見解。在創建基本決議器并正確回應 chunked[Transfer-Encoding:chunked header] 和固定長度流[Content-Length header] 標頭后,我注意到有時我的客戶端仍然會卡住并偶爾等待 5 秒,有時會作業沒有問題。
在除錯com.sun.www.http.HttpURLConnection類數小時后,我意識到另一個缺陷不再是在服務器端,而是實際上在代碼的客戶端。尤其是這一點
con.getOutputStream().write("Hello".getBytes());
con.getOutputStream().flush();
con.getOutputStream().write("World".getBytes());
con.getOutputStream().flush();
con.getOutputStream().write("123".getBytes());
con.getOutputStream().flush();
我錯誤地認為這個類中的getOutputStream()會快取回傳的輸出流,但實際上它每次都回傳一個新的輸出流。
所以我不得不將代碼更改為此
OutputStream os=client.getOutputStream();
os.write("Hello".getBytes());
os.flush();
os.write("World".getBytes());
os.flush();
os.write("123".getBytes());
os.flush();
這終于解決了我所有的問題。適用于分塊和固定長度的流式傳輸
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/447347.html
