HTTP 是否允许服务器在使用所有输入之前启动输出?如果是这样,如何在 Java 中访问这样的服务器?



注意:这个问题与服务器是否可以在收到整个请求之前发送HTTP响应密切相关? 不同之处在于(1(我没有发送错误,我发送的是200 OK,(2(我同时控制客户端和服务器,所以并不真正关心浏览器支持。

上下文:我正在实现一个用于管理文件的Java HTTP客户端和服务器。特别是"上传"查询包含文件路径和文件正文,服务器使用文件的数字标识符进行响应。但是,如果已经上传了具有相同路径的文件,则服务器将仅使用先前生成的标识符进行响应。

具体来说:如果我按如下方式编写服务器(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()));

然后,由于连接关闭,在copy操作期间抛出IOException。在那之后,我将无法再访问连接的InputStream

的问题:我怎样才能做到这一点?如果我更改服务器以消耗整个输入并将其丢弃,它可以工作,但感觉像是在浪费资源(上传的某些文件可能是重达数百兆字节的视频(。有没有办法更改客户端代码来处理这种情况?

假设文件足够大,并且发出多个请求消耗的资源远少于传输部分文件,则可以将该调用分解为多个请求。

enum UploadStatus {
INITIALIZED,
STARTED,
UPLOADED,
ERROR
}

我的建议:

  1. 具有静态映射ConcurrentMap<File name string, UploadStatus>(或数据库( 条目(,您可以在其中跟踪文件上传状态
  2. 创建终结点以检查和设置文件状态
  3. 客户端首先向上述终结点发出请求
    • 如果文件存在于地图上并且其状态不是UploadStatus.ERROR,则将文件在地图上的状态设置为UploadStatus.INITIALIZED,并让客户端(客户端 A(知道它可以上传文件(应该在synchronized块上执行此操作(
  4. 如果文件存在且UploadStatus.INITIALIZED,请让该客户端(客户端 B(知道它正在上传。为了用户体验,您可以让客户端 B 轮询文件状态,直到UploadStatus变得ERRORUPLOADED,然后采取适当的操作。
    • UploadStatus.ERROR上重新上传文件
    • UploadStatus.UPLOADED上显示上传的消息
  5. 服务器收到从客户端 A 上传实际文件的请求后,请使文件上传状态保持最新,以便在出现错误时其他客户端(如客户端 B(可以重新上传失败的文件。

在单个同步块上执行文件状态检查和设置对于在设置正确的文件状态时避免争用情况非常重要。此外,该枚举只是为了解释一般的高级步骤。由于您已经拥有番石榴,因此您可以使用番石榴缓存和时基逐出来存储文件雕像。

相关内容

  • 没有找到相关文章

最新更新