【发布时间】:2019-06-09 00:25:28
【问题描述】:
今天早上我用 Java 编写了一个自定义服务器。最终,我想将它用作 react-native 应用程序的后端,因此我致力于实现文件上传。我一直在用一个简单的 HTML 表单对此进行测试,该表单将其数据提交到我的本地机器。在解析 HTTP 请求标头时,我提取请求的数据部分的 Content-Length(以下称为请求的“消息体”)。有时,HTTP 请求的消息体包含文件名和内容,但通常它是空的,即使 Content-Length 和 Content-Type(包括表单边界)设置正确(非零长度, “--WebKitBoundary...” 边界)。我可以检测到这个和超时(不,增加我的超时不会让我读取更多数据),但是 HTTP 请求似乎表明应该有数据时没有收到数据这一事实似乎是一个重大问题。
here 的帖子似乎正是我所看到的,但截至发帖时尚未得到答复。
这是我用来从已建立的 Socket 连接的 InputStream 中读取数据的类:
public class HTTPRequest {
// full request, HTTP verb + URI, meta-data, message body
public final String request, requestline, headers, data;
// regex to find the length of the message body
private static final Pattern contentlength = Pattern.compile("Content-Length\\s*:\\s*(\\d+)");
/*
* when an object is created it reads the entire HTTP request from the stream and sets its constant strings accordingly
*/
public HTTPRequest(InputStream is) throws Exception {
/*
* get everything except the message body
*/
@SuppressWarnings("resource") // closing the Scanner closes the stream, so suppressing the resource leak warning
Scanner s = new Scanner(is);
requestline = s.nextLine();
s.useDelimiter("\r\n\r\n");
headers = s.next();
// get the reported length of the message body, 0 if not present
Matcher m = contentlength.matcher(headers);
int length = 0;
if(m.find()) {
length = Integer.parseInt(m.group(1));
}
// if there is a message body, read it
if(length > 0) {
// this will contain the message bytes
byte[] b = new byte[length];
// number of bytes read, number of consecutive times I read 0 bytes
int read = 0;
int numzeros = 0;
// read until I've read the entire message
while(read < length) {
// read however many bytes are available
int numread = is.read(b, read, is.available());
read += numread;
if(numread == 0) {
numzeros++;
}else {
numzeros = 0;
}
// timeout after not getting any data for 1 second
if(numzeros > 100) {
break;
}
Thread.sleep(10);
}
data = new String(b, 0, read);
// otherwise, no message body
}else {
data = "";
}
// combine all of the parts of the request
request = requestline + "\r\n" + headers + "\r\n\r\n" + data;
}
}
这是我用来上传文件的 HTML:
<head>
</head>
<body>
<form action="http://localhost:54600/api/test/test/uploadFile" method="post" enctype="multipart/form-data">
<input name="name" type="text" />
<input name="upload" type="file" />
<input type="submit" />
</form>
</body>
这是我从 InputStream 中读取的内容:
POST /api/test/test/uploadFile HTTP/1.1
Host: localhost:54600
Connection: keep-alive
Content-Length: 531
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzkLQnlCjBb2a5sOP
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
除了没有任何消息正文之外,这似乎是正确的。今天早些时候,我发现如果我每次提交表单时都上传一个唯一的文件,我通常会得到一个消息正文(多次提交同一个文件往往没有消息正文,尽管偶尔会有)。现在,我似乎根本无法获得消息正文。
更新,在写完最后一段之后,我决定在另一个标签中进行更多测试。这一次,我得到了一个消息体:
POST /api/test/test/uploadFile HTTP/1.1
Host: localhost:54600
Connection: keep-alive
Content-Length: 1162
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryErwo4zpzcDBuyDo5
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
------WebKitFormBoundaryErwo4zpzcDBuyDo5
Content-Disposition: form-data; name="name"
test_name
------WebKitFormBoundaryErwo4zpzcDBuyDo5
Content-Disposition: form-data; name="upload"; filename="hello_world.o"
Content-Type: application/octet-stream
ELF [... binary data]
------WebKitFormBoundaryErwo4zpzcDBuyDo5--
我在这个新标签中测试了更多,大部分时间我得到了表单数据,但我已经看到它没有发送消息正文两三次。当表单提交不包含消息正文时,似乎没有可辨别的模式。
有人对可能发生的事情有任何想法吗?
谢谢!
【问题讨论】: