Http协议+文件上传、下载、断点续传
Http协议
Http:超文本传输协议。
请求协议 request:
1、请求首行 (请求方式+网址+协议版本号)
2、请求头信息 (客户端告诉服务端的一些基本信息)
3、空行
4、请求体 (客户端向服务器提交的数据)
响应协议 response:
1、响应首行 (协议版本号+响应码+响应码描述) 200:成功 ,4xx:客户端错误,5xx:服务器错误,302:重定向 ,1xx:指示信息
2、响应头信息 服务器告诉客户端的一些信息 :Content-Length:2100846 返回数据大小
3、空行
4、响应体 服务端返回给客户端的数据
get和post的区别:
1、get没有请求体,post有请求体。
2、get向服务器要数据,post向服务器提交数据(登陆、注册、上传文件、头像)
3、get将请求参数暴露在url,不安全,post将请求参数放在请求体里面,安全。
文件下载
权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
DownLoadThread:
package com.example.day1.thread;
import android.os.Handler;
import android.os.Message;
import com.example.day1.MainActivity;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class DownLoadThread extends Thread{
private String url; //网址
private String path;//文件路径
private Handler handler;
public DownLoadThread(String url, String path, Handler handler) {
this.url = url;
this.path = path;
this.handler = handler;
}
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setReadTimeout(5000);
connection.setConnectTimeout(5000);
connection.connect();
if (connection.getResponseCode()==200) {
//获得总文件大小 - 发送
int max = connection.getContentLength();
Message message = new Message();
message.what= MainActivity.SEEKBAR_MAX;
message.obj=max;
handler.sendMessage(message);
InputStream is = connection.getInputStream();
FileOutputStream fos = new FileOutputStream(path);
byte[] bys = new byte[1024];
int len=0;
int count=0;
while ((len=is.read(bys))!=-1) {
fos.write(bys,0,len);
count+=len;
//发送读取长度
Message message1 = new Message();
message1.what= MainActivity.SEEKBAR_COUNT;
message1.obj=count;
handler.sendMessage(message1);
if (count==len) {
//下载完成
Message message2 = new Message();
message2.what= MainActivity.SEEKBAR_FINISH;
handler.sendMessage(message2);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
文件上传
需要设置请求头、请求体信息。
1.设置请求头信息:
Content-Length:请求体的总长度
Content-Type:multipart/form-data; boundary=7e324741816d4
2.请求体:2部分
第一部分:要有换行
-----------------------------7e324741816d4
Content-Disposition: form-data; name=“file”; filename=“上传到服务器的名字”
Content-Type: media/mp4或者media/mp3或者image/mp3或者image/png
空行
UpLoadThread:
package com.example.day1.thread;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class UpLoadThread extends Thread{
String url; // 网址
String path; //文件路径
String filename; //文件名
private Handler handler;
public UpLoadThread(String url, String path, String filename, Handler handler) {
this.url = url;
this.path = path;
this.filename = filename;
this.handler = handler;
}
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
//
//TODO 第一部分
// -----------------------------7e324741816d4
// Content-Disposition: form-data; name="file"; filename="上传到服务器的名字"
// Content-Type: media/mp4或者media/mp3或者image/mp3或者image/png
StringBuffer sb = new StringBuffer();
sb.append("-----------------------------7e324741816d4"+"\r\n");
sb.append("Content-Disposition: form-data; name=\"file\"; filename=\""+filename+"\""+"\r\n");
sb.append("Content-Type: image/jpg"+"\r\n");
sb.append("\r\n");
byte[] bytes = sb.toString().getBytes();
//TODO 请求头信息
// Content-Length:请求体的总长度
// Content-Type:multipart/form-data; boundary=7e324741816d4
Log.d("ytx", "run: "+(bytes.length+new File(path).length()));
connection.setRequestProperty("Content-Length",bytes.length+new File(path).length()+"");
connection.setRequestProperty("Content-Type","multipart/form-data; boundary=7e324741816d4");
//TODO POST请求
connection.setRequestMethod("POST");
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
os.write(bytes);
//边读边发
FileInputStream fis = new FileInputStream(path);
byte[] bys = new byte[1024];
int len=0;
int count=0;
while ((len=fis.read(bys))!=-1) {
os.write(bys,0,len);
count+=len;
}
Log.d("ytx", "run: "+(count+bytes.length));
//发起连接
connection.connect();
if (connection.getResponseCode()==200) {
Log.i("TAG", "上传成功 ");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
MainActivity:
new UpLoadThread("http://169.254.113.244/1705hfs/","/sdcard/Pictures/QQ图片20181212140907.jpg","yu.jpg",handler).start();
断点续传
设置请求头:
Range:bytes=起始位置-终点位置。
随机访问流:
RandomAccessFile(文件路径,“rw”)
seek(start) 从指定位置开始写
DuanDianThread:
package com.example.day1.thread;
import android.os.Handler;
import android.os.Message;
import com.example.day1.MainActivity;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class DuanDianThread extends Thread{
String url;
String path;
private Handler handler;
public DuanDianThread(String url, String path, Handler handler) {
this.url = url;
this.path = path;
this.handler = handler;
}
@Override
public void run() {
int start =0;
int end=0;
//先获取总长度
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setReadTimeout(5000);
connection.setConnectTimeout(5000);
connection.connect();
if (connection.getResponseCode()==200) {
end=connection.getContentLength();
}
//将总长度发给主线程设置给进度条
Message obtain = Message.obtain();
obtain.what= MainActivity.SEEKBAR_MAX;
obtain.obj=end;
handler.sendMessage(obtain);
//第二次请求
HttpURLConnection c = (HttpURLConnection) new URL(url).openConnection();
File file = new File(path);
if (file.exists()) {
//该文件已存在,断点续传
start= (int) file.length();
}
c.setRequestProperty("Range","bytes="+start+"-"+end);
if (c.getResponseCode()==206) {
InputStream is = c.getInputStream();
//随机访问流
RandomAccessFile randomAccessFile = new RandomAccessFile(path, "rw");
randomAccessFile.seek(start);
byte[] bys = new byte[1024];
int len=0;
int count=start;
while ((len=is.read(bys))!=-1) {
randomAccessFile.write(bys,0,len);
count+=len;//实时更新
//发送消息给主线程更新进度条
Message obtain1 = Message.obtain();
obtain1.what=MainActivity.SEEKBAR_COUNT;
obtain1.obj=count;
handler.sendMessage(obtain1);
//判断是否下载完毕
if (start==end) {
handler.sendEmptyMessage(MainActivity.SEEKBAR_FINISH);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
handler进度条更新
Handler handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what==SEEKBAR_MAX) {
Log.i("TAG", "设置最大长度 "+msg.obj);
seekBar2.setMax((Integer) msg.obj);
} else if (msg.what==SEEKBAR_COUNT) {
Log.i("TAG", "设置读取"+msg.obj);
seekBar2.setProgress((Integer) msg.obj);
}else if (msg.what==SEEKBAR_FINISH) {
Log.i("TAG", "设置读取"+msg.obj);
Toast.makeText(MainActivity.this, "下载完毕", Toast.LENGTH_SHORT).show();
}
}
};
网络七层
应用层:应用程序,用户看的见 http协议
表示层:将人看的懂的转成计算机看的懂
会话层:发起一个连接
传输层:规定传输协议和端口号 tcp协议 udp协议
网络层:规定网络ip ip协议
数据链路层:
物理层:光缆、网线
7种请求方式:
1、OPTIONS
返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性
2、HEAD
向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。
3、GET
向特定的资源发出请求。它本质就是发送一个请求来取得服务器上的某一资源。资源通过一组HTTP头和呈现数据(如HTML文本,或者图片或者视频等)返回给客户端。
4、POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。
5、PUT
向指定资源位置上传其最新内容
6、DELETE
请求服务器删除Request-URL所标识的资源
7、TRACE
回显服务器收到的请求,主要用于测试或诊断
8、CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
常见的响应码
1xx:指示信息
200:成功 ,
302:重定向 ,
4xx:客户端错误,
5xx:服务器错误,