基于Range协议的文件下载
2016-05-21 14:35
477 查看
当http请求头中包含
时,若响应头为
则代表该资源支持切片下载。只需要在请求头中加入
服务端就会响应给定的范围内的资源。
HTTP Range文件下载示例:
Accept-Ranges: bytes
时,若响应头为
HTTP/1.1 206 Partial Content
则代表该资源支持切片下载。只需要在请求头中加入
Range: bytes=start-end
服务端就会响应给定的范围内的资源。
HTTP Range文件下载示例:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import com.jfinal.plugin.ehcache.CacheKit; import com.sdzn.iload.model.FileBean; import com.sdzn.iload.model.ResultEnum; public class HttpClient { private static final Logger log = Logger.getLogger(HttpClient.class); private static RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(5000).build(); /** * 获取文件下载信息 * * @param fb */ public static void getFileOption(FileBean fb) { HttpGet httpget = new HttpGet(fb.getFileUrl()); httpget.setConfig(requestConfig); CloseableHttpResponse response = null; CloseableHttpClient httpclient = null; try { httpclient = HttpClients.createDefault(); response = httpclient.execute(httpget); if (response.getStatusLine().getStatusCode() == 200) { fb.setContentLength(Long.parseLong(response.getFirstHeader( "Content-Length").getValue())); fb.setStart(0l); fb.setEnd(fb.getContentLength()); fb.seteTag(response.getFirstHeader("ETag").getValue()); System.out.println(response.getFirstHeader("Accept-Ranges") .getValue()); if (response.getFirstHeader("Accept-Ranges").getValue() .equalsIgnoreCase("bytes")) { fb.setRange(true); } fb.setResult(ResultEnum.GET_INFO_SUCCESS.getValue()); } else { fb.setResult(ResultEnum.GET_INFO_FAIL.getValue()); } } catch (Exception e) { log.error("获取下载信息失败", e); fb.setResult(ResultEnum.GET_INFO_FAIL.getValue()); } finally { closeHttpClient(httpclient); closeHttpResponse(response); } } /** * 支持断点的文件下载 * * @param fb */ public static void getRangeFile(FileBean fb) { CloseableHttpClient httpclient = null; CloseableHttpResponse response = null; HttpEntity entity = null; Path savePath = Paths.get(fb.getSaveUrl()); Path fileName = savePath.getFileName(); String tempName = StringUtil.replaceSuffix(fileName.toString(), "tmp"); // 临时文件 Path tempPath = Paths.get(savePath.getParent().toString(), tempName); fb.setTempPath(tempPath.toString()); try { if (!Files.exists(tempPath)) { tempPath = createFile(tempPath); } httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet(fb.getFileUrl()); httpget.setConfig(requestConfig); StringBuilder sb = new StringBuilder(); sb.append("bytes=").append(fb.getStart()).append("-") .append(fb.getEnd()); httpget.setHeader("Range", sb.toString()); response = httpclient.execute(httpget); entity = response.getEntity(); if ((response.getStatusLine().getStatusCode() == 200 || response .getStatusLine().getStatusCode() == 206) && entity.getContentLength() > 0 && response.getFirstHeader("ETag").getValue() .equals(fb.geteTag())) { try (FileChannel fc = FileChannel.open(tempPath, StandardOpenOption.WRITE, StandardOpenOption.SYNC); InputStream is = entity.getContent();) { fc.position(fb.getStart()); // fc.force(true); byte[] read = new byte[8192]; int len = is.read(read); while (len > 0) { fc.write(ByteBuffer.wrap(read, 0, len)); fb.addRateLength((long) len); if (fb.isCut()) { FileBean p = CacheKit.get("FILEBEAN", fb.getParentTaskId()); if (p != null) { p.addRateLength((long) len); p = CacheKit.get("FILEBEAN", fb.getParentTaskId()); } } if (!fb.getRunStatus()) { len = is.read(read); } else { len = 0; } } } log.info("rate:" + fb.getRateLength() + ";len:" + fb.getContentLength()); if (fb.getRunStatus()) { fb.setResult(ResultEnum.STOP.getValue()); } else if (fb.getRateLength().equals(fb.getContentLength())) { fb.setResult(ResultEnum.SUCCESS.getValue()); } else { fb.setResult(ResultEnum.FAIL.getValue()); } } else { fb.setResult(ResultEnum.NOTFEXP.getValue()); } } catch (Exception e) { log.error("下载文件失败!", e); fb.setResult(ResultEnum.EXP.getValue()); } finally { closeHttpClient(httpclient); closeHttpResponse(response); consumeEntity(entity); } } /** * 下载任务 * * @param fb */ public static void getFile(FileBean fb) { CloseableHttpClient httpclient = null; CloseableHttpResponse response = null; HttpEntity entity = null; Path savePath = Paths.get(fb.getSaveUrl()); Path fileName = savePath.getFileName(); String tempName = StringUtil.replaceSuffix(fileName.toString(), "tmp"); // 下载临时文件 Path tempPath = Paths.get(savePath.getParent().toString(), tempName); try { if (!Files.exists(tempPath)) { tempPath = Files.createFile(tempPath); } httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet(fb.getFileUrl()); httpget.setConfig(requestConfig); response = httpclient.execute(httpget); entity = response.getEntity(); if (response.getStatusLine().getStatusCode() == 200 && entity.getContentLength() > 0 && response.getFirstHeader("ETag").getValue() .equals(fb.geteTag())) { try (InputStream in = entity.getContent(); OutputStream os = Files.newOutputStream(tempPath);) { byte[] read = new byte[8192]; int length = in.read(read); while (length > 0) { os.write(read, 0, length); fb.addRateLength((long) length); if (!fb.getRunStatus()) { length = in.read(read); } else { length = 0; fb.setResult(ResultEnum.STOP.getValue()); } } } if (fb.getRateLength().equals(fb.getContentLength())) { fb.setResult(ResultEnum.SUCCESS.getValue()); // 修改临时文件名 tempPath.toFile().renameTo(savePath.toFile()); } else { fb.setResult(ResultEnum.FAIL.getValue()); } } else { fb.setResult(ResultEnum.NOTFEXP.getValue()); } } catch (Exception e) { log.error("下载文件失败!", e); fb.setResult(ResultEnum.IOEXP.getValue()); } finally { closeHttpClient(httpclient); closeHttpResponse(response); consumeEntity(entity); if (!fb.getResult().equals(ResultEnum.SUCCESS.getValue())) { deletePathIfExists(tempPath); } } } private static void closeHttpClient(CloseableHttpClient client) { if (client != null) try { client.close(); } catch (IOException e) { } } private static void closeHttpResponse(CloseableHttpResponse response) { if (response != null) try { response.close(); } catch (IOException e) { } } private static void consumeEntity(HttpEntity entity) { if (entity != null) try { EntityUtils.consume(entity); } catch (IOException e) { } } private static void deletePathIfExists(Path path) { try { Files.deleteIfExists(path); } catch (IOException e) { } } private static synchronized Path createFile(Path path) throws IOException { if (!Files.exists(path)) { return Files.createFile(path); } return path; } }
相关文章推荐
- RPC failed; result=22, HTTP code = 411
- HTTP Header 属性列表
- nginx中http核心模块的配置指令2
- nginx中http核心模块的配置指令3
- nginx中http核心模块的配置指令4
- nginx中http的fastcgi模块的配置指令1
- 如何在 Linux 中快速地通过 HTTP 提供文件访问服务
- 深入HTTP head的使用详解
- Ruby程序中发送基于HTTP协议的请求的简单示例
- OBlog任意文件下载漏洞
- ASP 中使用 HTTP 协议发送参数详解
- C#基于socket模拟http请求的方法
- http www安全必备知识
- asp HTTP 500错误 常见问题分析
- http代理相关知识分析
- 在Node.js中使用HTTP上传文件的方法
- php错误提示failed to open stream: HTTP request failed!的完美解决方法