问题描述
这个问题不是关于 NanoHTTPD 如何提供流媒体内容,或者它如何在提供页面后保持 HTTP 套接字连接打开。
我非常负责任地使用 HTML.java 生成 HTML,方法是传入一个将所有内容组合成字符串的 Writer。
然后我的代码复制该字符串并将其放入 newFixedLengthResponse()
中,后者将 HTML 发送给客户端。
这意味着,在我的 HTML 生成器写入 Writer stringStream 的整个过程中,一个真正的流 - 网络浏览器的套接字 - 是打开的,什么也不做。虽然我的 stringStream 做了太多 - 缓冲越来越多的内存......
我不能自己找到那个套接字,然后把它放到我的 HTML 生成器中吗?这样,当我计算 html.div()
时,“
1 个答案:
答案 0 :(得分:0)
即使在虚拟内存和 TB RAM 的时代,流也比字符串更高效。当我最初发布这个问题时,我不小心没有注意到 HTTPSession 对象已经有一个 outputStream
成员。所以第一步是升级它。将此添加到 IHTTPSession:
OutputStream getoutputStream();
现在将其添加到 HTTPSession:
public OutputStream getoutputStream() {
return outputStream;
}
public final void sender(@NonNull OutputStream outputStream,@NonNull Runnable run) {
SimpleDateFormat gmtFrmt = new SimpleDateFormat("E,d MMM yyyy HH:mm:ss 'GMT'",Locale.US);
gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
if (status == null) {
throw new Error("sendResponse(): Status can't be null.");
}
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream,new ContentType(mimeType).getEncoding())),false);
pw.append("HTTP/1.1 ").append(status.getDescription()).append(" \r\n");
if (mimeType != null) {
printHeader(pw,"Content-Type",mimeType);
}
if (getHeader("date") == null) {
printHeader(pw,"Date",gmtFrmt.format(new Date()));
}
for (Entry<String,String> entry : header.entrySet()) {
printHeader(pw,entry.getKey(),entry.getValue());
}
for (String cookieHeader : cookieHeaders) {
printHeader(pw,"Set-Cookie",cookieHeader);
}
if (getHeader("connection") == null) {
printHeader(pw,"Connection",(keepAlive ? "keep-alive" : "close"));
}
long pending = data != null ? contentLength : 0;
if (requestMethod != Method.HEAD && chunkedTransfer) {
printHeader(pw,"transfer-encoding","chunked");
}
pw.append("\r\n");
pw.flush();
run.run(); // <-- your streaming happens here
outputStream.flush();
NanoHTTPD.safeClose(data);
} catch (IOException ioe) {
NanoHTTPD.LOG.log(Level.SEVERE,"Could not send response to the client",ioe);
}
}
请注意,我们可以剔除更多未使用的东西。例如,浏览器不值得知道 Content-Length;它只需要拉动页面,看看它会得到什么。
现在应用覆盖 .serve()
并使其看起来像这样:
public final Response serve(IHTTPSession session) {
OutputStream outputStream = session.getoutputStream();
newFixedLengthResponse("").sender(outputStream,() -> {
new OutputStreamWriter(outputStream).write("Yo,World!");
} ;
return null;
}
最后,为了防止 NanoHTTPD 对 null
进行 snit-fit,进入 HTTPSession 并用返回替换这个 throw
:
// throw new ResponseException(Status.INTERNAL_ERROR,"SERVER INTERNAL ERROR: Serve() returned a null response.");
return;
进一步清理显然是可能的,但基本原则仍然是,因为我的应用程序使用流(特别是 com.googlecode.jatl.HTML)来构建它的页面,网络浏览器可以绘制我们页面的顶部 而我们仍在生成页面的底部。
解决方法
即使在虚拟内存和 TB RAM 的时代,流也比字符串更高效。当我最初发布这个问题时,我不小心没有注意到 HTTPSession 对象已经有一个 outputStream
成员。所以第一步是升级它。将此添加到 IHTTPSession:
OutputStream getOutputStream();
现在将其添加到 HTTPSession:
public OutputStream getOutputStream() {
return outputStream;
}
并将此方法添加到响应中:
public final void sender(@NonNull OutputStream outputStream,@NonNull Runnable run) {
SimpleDateFormat gmtFrmt = new SimpleDateFormat("E,d MMM yyyy HH:mm:ss 'GMT'",Locale.US);
gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
if (status == null) {
throw new Error("sendResponse(): Status can't be null.");
}
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream,new ContentType(mimeType).getEncoding())),false);
pw.append("HTTP/1.1 ").append(status.getDescription()).append(" \r\n");
if (mimeType != null) {
printHeader(pw,"Content-Type",mimeType);
}
if (getHeader("date") == null) {
printHeader(pw,"Date",gmtFrmt.format(new Date()));
}
for (Entry<String,String> entry : header.entrySet()) {
printHeader(pw,entry.getKey(),entry.getValue());
}
for (String cookieHeader : cookieHeaders) {
printHeader(pw,"Set-Cookie",cookieHeader);
}
if (getHeader("connection") == null) {
printHeader(pw,"Connection",(keepAlive ? "keep-alive" : "close"));
}
long pending = data != null ? contentLength : 0;
if (requestMethod != Method.HEAD && chunkedTransfer) {
printHeader(pw,"Transfer-Encoding","chunked");
}
pw.append("\r\n");
pw.flush();
run.run(); // <-- your streaming happens here
outputStream.flush();
NanoHTTPD.safeClose(data);
} catch (IOException ioe) {
NanoHTTPD.LOG.log(Level.SEVERE,"Could not send response to the client",ioe);
}
}
请注意,我们可以剔除更多未使用的东西。例如,浏览器不值得知道 Content-Length;它只需要拉动页面,看看它会得到什么。
现在应用覆盖 .serve()
并使其看起来像这样:
public final Response serve(IHTTPSession session) {
OutputStream outputStream = session.getOutputStream();
newFixedLengthResponse("").sender(outputStream,() -> {
new OutputStreamWriter(outputStream).write("Yo,World!");
} ;
return null;
}
最后,为了防止 NanoHTTPD 对 null
进行 snit-fit,进入 HTTPSession 并用返回替换这个 throw
:
// throw new ResponseException(Status.INTERNAL_ERROR,"SERVER INTERNAL ERROR: Serve() returned a null response.");
return;
进一步清理显然是可能的,但基本原则仍然是,因为我的应用程序使用流(特别是 com.googlecode.jatl.HTML)来构建它的页面,网络浏览器可以绘制我们页面的顶部 而我们仍在生成页面的底部。