警告:这是一个自我回答的问题。我最近遇到了这个问题,发现它很棘手,虽然听起来很简单。我决定发布一个完整的问题和答案,为未来的访问者提供代码示例。
<小时/> 我有一个ServerSocket,它侦听端口12005上的连接。它以最简单的方式实现:
ServerSocket ss = new ServerSocket(12005);
while(true) {
executorService.submit(new SocketProcessor(ss.accept());
}
此处SocketProcessor
只是一个Runnable
,用于处理传入的连接:
@Override
public void run() {
try {
String msg = IOUtils.toString(s.getInputStream());
// process msg here
} finally {
s.close();
}
}
问题是执行在IOUtils.toString(InputStream is)
方法上挂起。我认为标准解决方案会更好,所以我用
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
输出类似于:
POST / HTTP/1.1
Host: http://localhost:12005
Content-Type: application/json
//other headers
<--- empty line
<--- here it hangs
如果我在调用者端中止连接,我可以在输出中看到一个新行 - 实际上它是http正文:
{"name":"alex", "hobby":"football"}
我尝试了两种不同的请求发送方实现,当我尝试读取http主体时它们都挂起了。这意味着问题正好在我的服务器套接字中。
这个实现从教程中出了什么问题?
答案 0 :(得分:0)
我很幸运能在reddit论坛找到解释。
简而言之,http post消息的结构如下
start-line CRLF
header-field-1 CRLF
header-field-2 CRLF
header-field-N CRLF
CRLF
message-body
正如您所看到的,邮件正文后面没有换行符号。因为这个readLine()
方法不能像我们预期的那样工作。我猜Apache IOUtils.toString()
方法面临同样的问题。要解决此问题,建议使用以下解决方案:
以下是示例代码:
BufferedReader br = new BufferedReader(new InputStreamReader(is));
boolean headersFinished = false;
int contentLength = -1;
while (!headersFinished) {
String line = br.readLine();
headersFinished = line.isEmpty();
if (line.startsWith("Content-Length:")) {
String cl = line.substring("Content-Length:".length()).trim();
contentLength = Integer.parseInt(cl);
}
}
// validate contentLength value
char[] buf = new char[contentLength]; //<-- http body is here
br.read(buf);