URLConnection 类
URLConnection 类:代表应用程序和URL之间的通信链接,此类的实例可用于读取和写入此URL引用的资源,创建到一个URL的连接的步骤
- 通过在 URL 上调用 openConnection 方法创建连接对象
- 处理设置参数和一般请求属性
- 使用connect方法建立到远程对象的实际连接
- 远程对象变为可用,远程对象的头字段和内容变为可访问
参数设置:
- setAllowUserInteraction:是否允许与用户交互,默认 false
- setDoInput:URLConnection可用于输入时设置为true,默认为true
- setDoOutput:URLConnection可用于输出时设置为true,默认为false
- setIfModifiedSince:将放置If-Modified-Since首部字段中的日期(格林威治标准时间1970年1月1日子夜后的毫秒数)
- setUseCaches:是否可以在缓存可用时使用缓存,默认为true,表示缓存将被使用;false表示缓存不被使用
- setConnectTimeout:设置获取连接的超时值,单位为ms
- setReadTimeout:设置获取读取的超时值,单位为ms
- setFollowRedirects(boolean set):true,允许跟随重定向
HttpURLConnecton 类
HttpURLConnection 类:可以实现简单的基于URL请求、响应功能
参数值设置:
- setRequestProperty(String key, String value):在首部设置一个值
- addRequestProperty(String key, String value):用于添加某个指定首部字段的值
- InputStream getInputStream():返回从此打开的连接读取的输入流
- OutputStream getOutputStream():返回写入到此连接的输出流
- setRequestMethod(String method):设置请求方法
- getResponseMessage():返回消息响应
- getResponseCode():返回消息响应码
- setInstanceFollowRedirects(boolean followRedirects):true,允许跟随重定向
- 若只是向服务器请求数据,则为HTTP请求方法为GET
- 若需要向服务器提交数据,必须在先调用setDoOutput(true)。当doOutput属性为true时,请求方法将由GET变为POST
单线程下载器
从给定的地址下载文件,有如下几个要点
- 如果传入的 URL 是一个动态网址,需要获取真实的网址,需要设置 URLConnection.setFollowRedirects(boolean set) 或者 HttpURLConnection.setInstanceFollowRedirects(boolean followRedirects) 允许跟随重定向,然后取得真实的下载地址
- 在下载文件时传入参数需要设置 Content-Length 属性
- 有些下载站可能有防盗链设置,因此最好设置 Referer:网站网址 属性
- 为了避免网站的反爬虫机制,最好添加浏览器代理
如果有需要,可以使用 curl 先进行测试:
- -I:只显示响应头信息
- -L:跟踪重定向
- —header “Referer: http://xiazai.zol.com.cn/“ :设置请求头属性,避免防盗链导致跳转到首页
public class Downloader {
private static HttpURLConnection connection(URL url) throws IOException {
// 1.获取连接
URLConnection urlConnection = url.openConnection();
// 2.获取HttpURLConnection
HttpURLConnection connection = (HttpURLConnection) urlConnection;
// 3.设置基础的连接参数
// 设置Referer参数,避免防盗链
connection.setRequestProperty("Referer", url.getHost());
// 设置用户代理
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36");
// 允许跟踪重定向
connection.setInstanceFollowRedirects(true);
return connection;
}
private static String getFileName(URL url) {
String path = url.getPath();
return path.substring(path.lastIndexOf("/") + 1);
}
private static volatile int count = 0;
private static void downloader(URL url) throws IOException {
/* 获取真实的下载地址 */
HttpURLConnection connection = connection(url);
connection.connect();
// 获取文件大小
long len = connection.getContentLengthLong();
// 获取真实的下载地址
URL urlTruth = connection.getURL();
// 获取文件名
String fileName = getFileName(urlTruth);
// 关闭连接
connection.disconnect();
System.out.println("真实的下载地址:" + urlTruth);
System.out.println("文件名:" + fileName);
System.out.println("文件大小" + len);
/* 开始下载 */
HttpURLConnection conn = connection(urlTruth);
// 设置Content-Length参数
conn.setRequestProperty("Content-Length", String.valueOf(len));
conn.connect();
try (BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));) {
byte[] bytes = new byte[1024];
int read = 0;
View view = new View();
// 设置为守护线程
view.setDaemon(true);
view.start();
while ((read = bis.read(bytes)) != -1) {
bos.write(bytes, 0, read);
count += read;
}
bos.flush();
}
}
// 监测线程
private static class View extends Thread {
@Override
public void run() {
while (!Thread.interrupted()) {
System.out.println("已经下载:" + count / 1024 + "KB");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws IOException {
URL url = new URL("http://down10.zol.com.cn/20180522/YunGameBoxSetup_dyg1167_yjwzgc.exe");
URL url1 = new URL("http://download.skycn.com/hao123-soft-online-bcs/soft/P/2014-05-22_PowerWord.100.exe");
URL url2 = new URL("http://xiazai.zol.com.cn/down.php?softid=428117&subcateid=1442&site=10&checkStr=28088c8250a5dcb30&pos=downloader_list&rand=4a6d84");
downloader(url2);
}
}
文件断点续传
文件端点续传实现原理:
- 如果响应头信息中存在“Accept-Ranges:bytes”属性,说明该网站支持断点续传
- 就是在请求时可以通过设置请求头属性“Range:bytes=0-xx”指定服务器传输的位置
以上面获得的真实地址为例,构建 curl 请求:
从上面的响应头信息中可以看到:
- 返回代码变成了 206 Partial Content
- Content-Range 属性变成了 100-1000/33082232