BufferedReader不能读取空行后面的内容

3

我正在尝试找出为什么我的BufferedReader(从InputStream读取)在接收到空行后会挂起并且不再继续读取。

试图读取类似以下POST请求的内容:

POST /test.php HTTP/1.0
Content-Length: 30
Content-Type: text/html;

postData=whatever&moreData...

我知道帖子数据以正确的格式被发送,但是我无法检索已发布的数据。我期望以下代码打印出帖子数据,然后挂起等待更多内容... 但实际上,它在“Content-Type”行之后挂起。

while (true) {
    System.out.println(bufferedReader.readLine());
}

用于获取流的代码:

bufferedReader = new BufferedReader(clientSocket.getInputStream());

有人知道为什么会发生这种情况吗?谢谢。

我预计的是bufferedReader = new BufferedReader( new URL( "http://..." ).openConnection()); 为什么要使用socket进行HTTP? - Aubin
服务器 - 我正在读取发送的POST请求 - 因此尝试读取已发布数据(在空行之后),但无法检索它。 - cud_programmer
如果这是服务器的一部分,为什么套接字句柄被称为clientSocket?这是否意味着“用于与客户端通信的套接字”? - seh
请在发送数据的客户端代码中包含您正在使用的代码。 - Perception
它是否打印空行?客户端是否关闭了套接字的一端?如果没有,您的InputStream将不会报告EOF,如果POST消息正文未由CR或LF终止,则BufferedReader将不会返回部分行的内容。 - seh
显示剩余2条评论
1个回答

4
POST方法不会在末尾添加换行符。需要做的是获取Content-Length并在最后一个空白行之后读取相应数量的字符。
例子:
假设我们有一个以下HTML页面:
<html>
<head/>
<body>
    <form action="http://localhost:12345/test.php" method="POST">
        <input type="hidden" name="postData" value="whatever"/>
        <input type="hidden" name="postData2" value="whatever"/>
        <input type="submit" value="Go"/>
    </form>
</body>
</html>

现在我们启动一个非常简单的服务器,它有点像你的代码(这段代码充满了漏洞,但这不是问题):
public class Main {
    public static void main(final String[] args) throws Exception {
        final ServerSocket serverSocket = new ServerSocket(12345);
        final Socket clientSocket = serverSocket.accept();
        final InputStreamReader reader = new InputStreamReader(clientSocket.getInputStream());
        final BufferedReader bufferedReader = new BufferedReader(reader);
        int contentLength = -1;
        while (true) {
            final String line = bufferedReader.readLine();
            System.out.println(line);

            final String contentLengthStr = "Content-Length: ";
            if (line.startsWith(contentLengthStr)) {
                contentLength = Integer.parseInt(line.substring(contentLengthStr.length()));
            }

            if (line.length() == 0) {
                break;
            }
        }

        // We should actually use InputStream here, but let's assume bytes map
        // to characters
        final char[] content = new char[contentLength];
        bufferedReader.read(content);
        System.out.println(new String(content));
    }
}

当我们在我们喜欢的浏览器中加载页面并按下“Go”按钮时,我们应该在控制台中看到POST请求体的内容。

我知道这只是示例代码,但是……在“Content-Length”头字段的冒号后面不需要空格,根据RFC 2616 §4.2。此外,为了方便未来想要借鉴我们的代码的读者,"Content-Length"头部并不是必须用来指示消息体的边界。RFC 2616 §4.4定义了四个选项:一个“Content-Length”头部、分块传输编码、"multipart/byteranges"媒体类型或客户端终止连接并向服务器指示EOF。http://www.ietf.org/rfc/rfc2616.txt - seh
@seh 嗯,基本上我不想包含一个完整的HTTP服务器的代码。这个例子旨在说明为什么OP的代码不起作用以及在非常有限的情况下可能的解决方案。 - ShyJ
那就是问题所在 - 我没有使用InputStream通过读取char/byte数组。谢谢! - cud_programmer
@seh我给出的只是代码的一小部分 - 我知道其他部分是有效的,因为我已经对它们进行了测试,只是提取这个发布的数据是问题所在。但现在全部解决了 :) - cud_programmer
"if (line.length() == 0)" 这根本不是你想要的。长度为零的行是完全可能的,这并不意味着没有更多的内容... - Alkanshel
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接