<
audio
src
=
"http://www.test.com/test.mp3"
controls
=
"controls"
>
Your browser does not support the audio element.
</
audio
>
</
body
>
</
html
>
复制代码
按照一般思路,直接把文件的字节数组或者字节流响应给客户端就能实现。然而safari采用的是Range请求(不了解Range请求请自己百度),分段下载资源。它首先获取资源的Content-Length,然后根据资源的大小,分多次请求下载。比如资源的大小是100,第一次下载0-50,第二次下载51-100。我猜测这应该就是流式视频的原理。对于用户而言可以边播放,边下载。这无疑大大提高了用户体验。
下面是java的具体代码实现(chrome同样支持)。修改之后也适用于视频播放(参考自:
blog.csdn.net/u010120886/…
,同时我做了部分修改):
@GetMapping("/download")
public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
String range = request.getHeader("Range");
byte [] bytes = getBytes();
long contentLength = bytes.length;
int start = 0, end = 0;
if(range != null && range.startsWith("bytes=")){
String[] values = range.split("=")[1].split("-");
start = Integer.parseInt(values[0]);
if(values.length > 1){
end = Integer.parseInt(values[1]);
int requestSize = 0;
if(end != 0 && end > start){
requestSize = end - start + 1;
} else {
requestSize = Integer.MAX_VALUE;
final int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
response.setContentType("audio/mpeg");
response.setHeader("Accept-Ranges", "bytes");
response.setHeader("ETag", sessionId);
response.setHeader("Last-Modified", new Date().toString());
if(range == null){
response.setHeader("Content-length", contentLength + "");
response.getWriter().flush();
response.getWriter().close();
return;
}else{
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
long requestStart = 0, requestEnd = 0;
String[] ranges = range.split("=");
if(ranges.length > 1){
String[] rangeDatas = ranges[1].split("-");
requestStart = Integer.parseInt(rangeDatas[0]);
if(rangeDatas.length > 1){
requestEnd = Integer.parseInt(rangeDatas[1]);
long length = 0;
if(requestEnd > 0){
length = requestEnd - requestStart + 1;
response.setHeader("Content-length", "" + length);
response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
}else{
length = contentLength - requestStart;
response.setHeader("Content-length", "" + length);
response.setHeader("Content-Range", "bytes "+ requestStart + "-" + (contentLength - 1) + "/" + contentLength);
ServletOutputStream out = response.getOutputStream();
int needSize = requestSize;
if (end != 0) {
bytes = ArrayUtils.subarray(bytes, start, end + 1);
int i = 0;
while(needSize > 0){
int beginIndex = i * bufferSize;
int endIndex = (i + 1) * bufferSize;
if (endIndex > bytes.length) {
endIndex = bytes.length;
buffer = ArrayUtils.subarray(bytes, beginIndex, endIndex);
int len = endIndex - beginIndex;
if(needSize < buffer.length){
out.write(buffer, 0, needSize);
} else {
out.write(buffer, 0, len);
if(len < buffer.length){
break;
needSize -= buffer.length;
out.close();
复制代码