[英]Http client receives no response when server reads only headers from request
我搞砸了Java中的HTTP和套接字,希望您能對此有所了解:
當我用Java SE 11編寫的HTTP服務器未讀取整個請求然后進行響應時,客戶端將無法獲取該請求或發生錯誤。 這是為什么? 在服務器讀取整個請求之前,客戶端是否無法讀取響應? 如果在以下代碼段中執行了對readBody的調用,則可以正常工作。 如果響應具有Content-Length標頭和文本正文,它也可以正常工作。 這實際上讓我感到困惑。
我的示例請求是帶有數據fds的POST。 郵遞員說“無法收到任何請求”,而curl說“卷曲:(56)接收失敗:對等重置連接”。
import java.io.*;
import java.net.Socket;
import java.util.*;
class Handler {
public synchronized void read(Socket incoming) {
try (incoming;
OutputStream outputStream = incoming.getOutputStream();
InputStream inputStream = incoming.getInputStream();
PrintWriter pw = new PrintWriter(outputStream)) {
writeRequest(inputStream);
pw.print("HTTP/1.1 200 OK\r\n");
pw.print("\r\n");
pw.flush();
} catch (IOException e) {
System.out.println("ERROR: " + e.getMessage());
e.printStackTrace();
}
}
private void writeRequest(InputStream inputStream) throws IOException {
String verbLine = readLine(inputStream);
Map<String, String> headers = readHeaders(inputStream);
//readBody(inputStream, headers);
}
private void readBody(InputStream inputStream, Map<String, String> headers) throws IOException {
Optional<String> optKey = headers.keySet().stream()
.filter(k -> k.equalsIgnoreCase("Content-Length"))
.findFirst();
if (optKey.isPresent()) {
int contentLength = Integer.parseInt(headers.get(optKey.get()));
byte[] bytes = inputStream.readNBytes(contentLength);
}
}
private Map<String, String> readHeaders(InputStream inputStream) throws IOException {
Map<String, String> headers = new HashMap<>();
while (true) {
String line = readLine(inputStream);
if (line == null || line.isEmpty()) {
return headers;
}
String key = line.split(":")[0].trim();
String value = line.split(":")[1].trim();
headers.put(key, value);
}
}
private String readLine(InputStream inputStream) throws IOException {
byte[] buf = new byte[200];
int offset = 0;
while (true) {
int read = inputStream.read();
if (read == -1) {
return null;
}
buf[offset] = (byte) read;
if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n')) {
return "";
}
if (buf[offset] == 0x0A) {
int endOfLine = buf[offset - 1] == 0x0D ? offset - 1 : offset;
return new String(buf, 0, endOfLine);
} else {
offset++;
}
}
}
}
如果在服務器上仍然有未讀數據的情況下關閉套接字,則會導致客戶端連接重置錯誤。 因為您沒有閱讀完整的請求,所以在這里發生。 如果尚未讀取服務器的完整響應,則該錯誤將向用戶顯示。
如果您發送帶有content-length
的響應,然后發送完整的正文,則客戶端將讀取完整的響應,因此錯誤將被忽略。 相反,如果您既不發送content-length
也不使用分塊編碼,則客戶端將期望響應以正確關閉TCP連接結束。 在這種情況下,由於尚未(正確)讀取服務器的完整響應,因此連接重置將傳播給用戶。
您的響應需要具有Content-Length標頭或Transfer-Encoding標頭-告訴客戶端如何傳輸響應並允許其確定何時已接收所有字節。 否則,它將需要等待EOF並假定響應主體被EOF終止(這是為了與HTTP / 1.0兼容)。 您的客戶可能不支持。 了解您正在使用哪個客戶端可能會有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.