注:此问题与Is it acceptable for a server to send a HTTP response before the entire request has been received?密切相关,不同之处在于(1)我没有发送错误,我发送了200 OK,(2)我同时控制了客户端和服务器,因此不必太在乎浏览器支持。
Context:我正在实现Java HTTP客户端和服务器来管理文件。特别地,“上传”查询包含文件路径和文件主体,并且服务器以文件的数字标识符响应。但是,如果已经上传了具有相同路径的文件,则服务器将仅使用先前生成的标识符进行响应。
Concretely:如果我按如下方式编写服务器(sparkjava)
put(url, (req, res) -> {
Item existing = lookForExistingItem(req);
if (existing != null) {
return existing.getId();
}
/* Otherwise, consume input, save, generate id and return that */
});
...,然后服务器将以id响应并在客户端完成发送数据之前关闭连接。如果我按如下方式编写客户端:
final HttpURLConnection connection = (HttpURLConnection) new URL(...).openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
ByteStreams.copy(fileInput, connection.getOutputStream());
final String response = CharStreams.toString(new InputStreamReader(connection.getInputStream()));
然后由于关闭的连接在IOException
操作期间抛出了copy
。此后,我将无法再访问连接的InputStream
。
我的问题:如何进行这项工作?如果我更改服务器以消耗整个输入并将其丢弃,它就可以工作,但是感觉就像浪费资源(某些上传的文件可能是重达数百兆的视频)。有什么方法可以更改客户端代码以应对这种情况?
假设文件足够大,并且与传输部分文件相比,发出多个请求所消耗的资源要少得多,因此您可以将该调用拆分为几个请求。
enum UploadStatus {
INITIALIZED,
STARTED,
UPLOADED,
ERROR
}
我的建议:
ConcurrentMap<File name string, UploadStatus>
(或DB条目),您可以在其中跟踪文件的上传状态UploadStatus.ERROR
,请将文件在地图上的状态设置为UploadStatus.INITIALIZED
,并让客户端(客户端A)知道它可以上传文件(应在synchronized
上执行此操作块)UploadStatus.INITIALIZED
,请让该客户端(客户端B)知道其正在上传。对于UX,可以使客户端B轮询文件状态,直到UploadStatus
变为ERROR
或UPLOADED
,然后采取适当的措施。即UploadStatus.ERROR
上重新上传文件UploadStatus.UPLOADED
上显示上传的消息进行文件状态检查并在单个同步块上进行设置对于避免在设置正确的文件状态时出现竞争状态很重要。另外,该枚举仅用于解释一般的高级步骤。由于您已经拥有番石榴,因此可以将Guava Cache与时基逐出一起用于存储文件雕像。