[英]Simple web server hangs when receiving http request
我正在寫一個簡單的Web服務器,代碼片段:
ServerSocket server = new ServerSocket(80);
Socket client=server.accept();
InputStream in=client.getInputStream();
OutputStream out=client.getOutputStream();
int val = -1;
while ((val = in.read()) != -1) {
System.out.print((char) val);
}
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( out));
writer.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\nhello world!");
writer.close();
out.close();
in.close();
我在我的電腦上運行它,然后在Firefox中訪問http://127.0.0.1 。 頁面掛起,無法顯示“hello world”。我認為問題發生在while ((val = in.read()) != -1)
,如何解決?
HTTP(至少1.1版本)允許打開連接。 然后請求以空行結束(即"\\r\\n\\r\\n"
),如果它不是帶有內容的POST或PUT請求。 在此之后,客戶端可以在同一連接上發送下一個請求。
因此,您必須至少讀取輸入以掃描空行。
編輯:為了澄清這一點,來自RFC 2616 (定義HTTP 1.1)的一些引用。
部分4.1,消息類型 :
請求(第5節)和響應(第6節)消息使用RFC 822 [9]的通用消息格式來傳輸實體(消息的有效載荷)。 兩種類型的消息都包括一個起始行,零個或多個標題字段(也稱為“標題”),一個空行(即CRLF前面沒有任何內容的行),表示標題字段的結尾,可能還有一個郵件正文。
generic-message = start-line *(message-header CRLF) CRLF [ message-body ] start-line = Request-Line | Status-Line
因此,消息頭和消息體由空行(起始行之后的第一個)分隔。
第4.3節消息正文 :
HTTP消息的消息體(如果有的話)用於攜帶與請求或響應相關聯的實體體。 [...]
消息中允許消息正文的規則因請求和響應而異。
通過在請求的消息頭中包含Content-Length或Transfer-Encoding頭字段來指示請求中消息體的存在。 如果請求方法的規范(第5.1.1節)不允許在請求中發送實體主體,則消息主體不得包含在請求中。 服務器應該在任何請求上讀取和轉發消息體; 如果請求方法不包含實體主體的定義語義,那么在處理請求時應該忽略消息主體。
因此原則上,客戶端必須只在方法允許時發送一個正文,但是服務器應該忽略多余的消息體,如果它們是在不支持它的方法上發送的。 並且Content-Length
或Transfer-Encoding
頭字段指示正文的存在。
第9節的小節定義了各個方法。
無論如何,無論客戶端是否發送正文,以及它是否重新使用連接以進行下一個請求,通常都不會在讀取響應之前關閉連接,否則您的服務器根本無法重新發送響應。 因此,您在閱讀請求時無法等待結束,但必須以某種方式知道何時結束發送您的回復。
對於只處理獲取請求的簡單hello world服務器,您可以簡單地說“直到第一個空行”。
對於真實的服務器(即外部世界可見的服務器),您至少應該解析請求,忽略任何正文,並以不同於GET的方式處理HEAD(即,不發送任何正文),並發送錯誤響應不支持的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.