当http请求头中包含 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;

}

}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐