Android 通过post上传文件--HttpURLConnection实现

最近在做向服务器提交文件,本来用的xutils,使用起来挺简单,代码超不过10行,但是想深入了解一下原理,所以就自己用HttpURLConnection实现文件的上传。

无论是浏览器通过表单提交文件,还是APP通过post提交,其实原理都是一样的。APP只要仿照浏览器的表单提交数据的样式去提交文件,服务器就可以解析并处理文件。

那就首先来看一下浏览器提交的数据样式和请求头的信息。

HTML核心代码:


请求的头部信息:

host:192.168.218.163:8080

connection:keep-alive

content-length:432

cache-control:max-age=0

origin:null

upgrade-insecure-requests:1

user-agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36

content-type:multipart/form-data; boundary=----WebKitFormBoundarymYCoIxqCv49mE4Ok

accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

accept-encoding:gzip, deflate

accept-language:zh-CN,zh;q=0.8

cookie:__guid=158737658.212612550479137800.1501464417829.6194; monitor_count=15

头部信息的content-type是重点,如果是上传文件,表单的mime类型必须是multipart/form-data,“boundary”是用来隔开表单中不同部分数据的,它是由- -开头,而不是boundary数据开头,以- -结尾。

服务器获取到的数据:

------WebKitFormBoundarynug1Tk0jD0SCH33m

Content-Disposition: form-data; name="file"; filename="nuuid.ini"

Content-Type: application/octet-stream

 

##这是上传文件的数据##

------WebKitFormBoundarynug1Tk0jD0SCH33m--

上传文件,post出去的数据是比较严格的。数据必须以--boundary开头

每一条数据独占一行,内容描述信息样式:

Content-Disposition: form-data; name="file"; filename="nuuid.ini"

Content-Type: application/octet-stream

然后空一个空行(/r/n),再是具体的文件数据。然后- -boundary- -结尾。

下面开始写Java代码:

String uuid = UUID.randomUUID().toString();
        String BOUNDARY = uuid;
        String NewLine = "\r\n";
        String spec = "http://192.168.218.163:8080/Test/FileUpLoad";
        File file = new File("G:\\mv\\哥德巴赫猜想.txt");
        FileInputStream fis=null;
        DataOutputStream bos =null;
        DataInputStream bis=null;
URL url = new URL(spec);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			//打开输出
			connection.setDoOutput(true);
			//打开输入
			connection.setDoInput(true);
			//关闭缓存
			connection.setUseCaches(false);
			//读取超时
			connection.setReadTimeout(50*1000);
			//连接超时
			connection.setConnectTimeout(5*1000);
			//请求方式POST
			connection.setRequestMethod("POST");
			//设置请求头
//			connection.setRequestProperty("Connection", "Keep-Alive");
//connection.addRequestProperty("user-agent","Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; NX507J Build/KVT49L) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1");
			//必须设置,数据类型,编码方式,分界线
			connection.setRequestProperty("Content-Type", "multipart/form-data; charset=utf-8; boundary="+BOUNDARY);
//connection.setRequestProperty("accept-encoding","gzip"); 
			connection.setChunkedStreamingMode(1024 * 50);
			bos = new DataOutputStream(connection.getOutputStream());
			
			if (file.exists()) {
				fis = new FileInputStream(file);
				byte[]buff = new byte[1024];
				 bis = new DataInputStream(fis);
				int cnt=0;
				//数据以--BOUNDARY开始
				bos.write(("--"+BOUNDARY).getBytes());
				//换行
				bos.write(NewLine.getBytes());
				//内容描述信息
				content = "Content-Disposition: form-data; name=\""+filename+"\"; filename=\""+file.getName()+"\"";
				bos.write(content.getBytes());
				bos.write(NewLine.getBytes());
//				bos.write("Content-Type: application/octet-stream".getBytes());
//				bos.write(NewLine.getBytes());
//				bos.write("Content-Transfer-Encoding: binary".getBytes());
//				bos.write(NewLine.getBytes());
				bos.write(NewLine.getBytes());
            //空一行后,开始通过流传输文件数据
				while((cnt=bis.read(buff))!=-1){
					bos.write(buff,0,cnt);
				}
				bos.write(NewLine.getBytes());
				//结束标志--BOUNDARY--
				bos.write(("--"+BOUNDARY+"--").getBytes());
				bos.write(NewLine.getBytes());
				bos.flush();
			}
//开始发送请求,获取请求码和请求结果
			if (connection.getResponseCode()==HttpURLConnection.HTTP_OK) {
				connection.getInputStream();
				System.out.println("url="+connection.getURL());
				BufferedReader read = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
				String dat=null;
				while ((dat =read.readLine())!=null){
					System.out.println(dat);
				}
				System.out.println("请求成功");;
			}else {
				System.err.println("请求失败"+connection.getResponseMessage()+"code="+connection.getResponseCode());
			}

请求体的内容:

--32eeb4fb-7fe9-4fa3-a5bf-ec357c48a5d4

Content-Disposition: form-data; name="file"

Content-Type: text/plain; charset=utf-8

 

文本文件

--32eeb4fb-7fe9-4fa3-a5bf-ec357c48a5d4

Content-Disposition: form-data; name="哥德巴赫猜想.txt"; filename="哥德巴赫猜想.txt"

 

##上传文件的内容(文本或二进制)

--32eeb4fb-7fe9-4fa3-a5bf-ec357c48a5d4--

注:

1.post到服务器的数据格式要求严格,以--BOUNDARY开头,紧跟着是内容描述信息(Content-Disposition: form-data; name="filename"; filename=" ",然后空一行+内容正       文,--BOUNDARY--结尾。

2.注释的代码,是不必须的参数。

3.如果数据格式不按固定格式传输(描述信息和内容正文之间空一行),服务器在处理数据时会报Stream ended unexpectedly异常(服务器用的Apache FileUpload组件)

你可能感兴趣的:(Android开发,文件上传,POST)