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

  • Post author:
  • Post category:其他



最近在做向服务器提交文件,本来用的

xutils

,使用起来挺简单,代码超不过


10


行,但是想深入了解一下原理,所以就自己用


HttpURLConnection


实现文件的上传。


无论是浏览器通过表单提交文件,还是

APP

通过


post


提交,其实原理都是一样的。


APP


只要仿照浏览器的表单提交数据的样式去提交文件,服务器就可以解析并处理文件。

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


HTML

核心代码:

<form method="post" action="http://192.168.218.163:8080/Test/FileUpLoad" enctype="multipart/form-data">
<input type="file" name="file" size="20" ><br/>
<input type="submit" name="submit" value="提交">
</form>


请求的头部信息:

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

组件)




版权声明:本文为Gone_the_rainbow原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。