前言
这个问题不知道大家有没有遇到过,不过,我举例说明一下:
spring boot用这样的代码输出一个mp4文件到reponse,大概率
public static void outputFile(byte[] content,String fileName,String mimeType,Integer contentLength,HttpServletResponse response) {
response.setCharacterEncoding("utf-8");
// response.setContentType("application/octet-stream");
try {
// 清空response
response.reset();
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType(mimeType);
response.setContentLength(contentLength);
response.setHeader("Accept-Ranges","bytes");
// response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
toClient.write(content);
toClient.flush();
toClient.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
其中 mimeType 为 "video/mp4"
大概率可以在chrome,firefox,android上部分,99%没办法在safari以及ios上面播放。
好了,先看参考文章:
在苹果safari浏览器上video标签无法正常播放视频
好了,问题点已经提到了,就是要有accept-range的识别,要可以返回部分文件内容,即,实现http resultcode=206的协议。
一般情况用tomcat的默认处理器处理—为什么可以处理成功?因为人家早就实现了http所有协议,包括206协议啊。。。但是,假如这个文件一定要中转,那怎么做呢?
答案有一个,
自己实现partial content—resultcode=206的内容。
下面有文章可以参考:
java处理苹果浏览器safari无法播放视频流(Accept-Ranges)
原作者给出了代码:
private void sendVideo(HttpServletRequest request, HttpServletResponse response, File file, String fileName) throws FileNotFoundException, IOException {
RandomAccessFile randomFile = new RandomAccessFile(file, "r");//只读模式
long contentLength = randomFile.length();
String range = request.getHeader("Range");
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;
}
byte[] buffer = new byte[4096];
response.setContentType("video/mp4");
response.setHeader("Accept-Ranges", "bytes");
response.setHeader("ETag", fileName);
response.setHeader("Last-Modified", new Date().toString());
//第一次请求只返回content length来让客户端请求多次实际数据
if(range == null){
response.setHeader("Content-length", contentLength + "");
}else{
//以后的多次以断点续传的方式来返回视频数据
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
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;
randomFile.seek(start);
while(needSize > 0){
int len = randomFile.read(buffer);
if(needSize < buffer.length){
out.write(buffer, 0, needSize);
} else {
out.write(buffer, 0, len);
if(len < buffer.length){
break;
}
}
needSize -= buffer.length;
}
randomFile.close();
out.close();
---------------------
作者:通信二师
来源:CSDN
原文:https://blog.csdn.net/u010120886/article/details/79007001
版权声明:本文为博主原创文章,转载请附上博文链接!