netty文件添加断点续传
netty文件添加断点续传、netty文件服务器添加断点续传、netty返回mp4处理、netty播放视频、netty播放mp4、netty实现断点续传
如果请求的是媒体文件,需要进行断点续传的响应:断点续传百科:https://baike.baidu.com/item/%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0/764723
例如 /mp4.mp4
首先要在 pipeline
中添加大数据写处理,否则无法使用下面的断点功能:
ChannelPipeline p = ...;
p.addLast("streamer", new ChunkedWriteHandler());
p.addLast("handler", new MyHandler());
响应代码
public void returnStaticFile(FinalServerContext context, ChannelHandlerContext ctx) throws Exception {
File file = context.getResponse().getResponseFile().getFile();
if (!file.exists()) {
log.warn("文件不存在:{}", file.getAbsolutePath());
FinalServerConfiguration.webExceptionHandler.notHandler(ctx);
return;
}
HttpResponseStatus status = HttpResponseStatus.OK;
HttpHeaders headers = new DefaultHttpHeaders();
headers.set(HttpHeaderNames.ACCEPT_RANGES, HttpHeaderValues.BYTES);
headers.set(HttpHeaderNames.CONTENT_LENGTH, file.length());
headers.set(HttpHeaderNames.LAST_MODIFIED, file.lastModified());
headers.set(HttpHeaderNames.CACHE_CONTROL, HttpHeaderValues.PUBLIC);
// 设置文件请求头
HttpUtils.setResponseHeadName(context.getResponse().getResponseFile(), headers);
// 静态文件需要做到断点续传
String range = context.getRequest().getHeaders().get(HttpHeaderNames.RANGE);
long offset = 0L, length = file.length();
if (StrUtil.isNotBlank(range)) {// Range: bytes=1900544- Range: bytes=1900544-6666666
range = range.substring(6);
String[] split = range.split("-");
try {
offset = Long.parseLong(split[0]);
if (split.length == 2) {
long end = Long.parseLong(split[1]);
if (end <= length) {
headers.set(HttpHeaderNames.CONTENT_RANGE, "bytes " + range + "/" + file.length());
length = end - offset + 1;
}
} else {
headers.set(HttpHeaderNames.CONTENT_RANGE, "bytes " + offset + "-" + (length - 1) + "/" + file.length());
length = length - offset;
}
headers.set(HttpHeaderNames.CONTENT_LENGTH, length);// 重写响应长度
// status = HttpResponseStatus.PARTIAL_CONTENT; // 206
} catch (Exception e) {
log.warn("断点续传解析错误", e);
}
}
DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status);
response.headers().set(headers);
ctx.write(response);
RandomAccessFile accessFile = new RandomAccessFile(file, "r");
ctx.writeAndFlush(
ctx.writeAndFlush(
// new DefaultFileRegion(file, offset, length) // 零拷贝,部分系统可能不支持,低版本jdk6以下存在bug
new ChunkedFile(
accessFile, offset, length, 1024 * 64), // 正常发送文件块
ctx.newProgressivePromise()
).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
future.channel().close();
}
});
}
html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
hi
<video width="320" height="240" controls src="/mp4.mp4"></video>
</body>
</html>
响应结果