簡體   English   中英

服務器僅從請求中讀取標頭時,Http客戶端未收到任何響應

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM