最近在做项目的过程中,遇到了一个问题,就是如何从安卓端将图片上传到服务器。通过查阅资料后,在此将自己的收获整理总结一下。
HTTP报文的内容
在Web应用程序中,HTTP协议充当了信使的角色。客户端向服务器发起HTTP请求,服务器接收到请求后将所请求的数据写入HTTP响应报文中,再回送给客户端。那么,当向服务器上传一张图片时,HTTP报文是如何将图片“带给”服务器的呢?
首先,我们通过网页表单向服务器发送图片,来看一看HTTP报文的具体内容是什么.
这里我写了一个简单的登录表单:
输入相关数据,点击登录。
一个完整的HTTP请求包含如下内容:一个请求行,若干请求头,以及实体内容。这里我们主要关注一下请求头和实体内容部分。
我们看一下请求头中的Content-Type字段,它的值为: 没错了,Content-Type字段的作用就是告诉服务器,我传递的数据是什么,你应该以什么方式来接收我传递过去的数据。而它的值一般可以设置为“application/json","application/x-www-form-urlencoded”,“multipart/form-data”等,每种值对应的实体内容的格式都是不一样的。这里的值之所以设置为“multipart/form-data”,是因为它会指定传输的数据为二进制类型,这正好适合我们去传输图片,文件。
再看之后的boundary属性,它的值就是之前的那个字符串。
最后,还有一个地方需要注意一下。在Request Payload中,除了分隔符之外,不同的表单项需要设置的请求头是不同的。如用户名和密码这样的表单项,只需要设置Content-Disposition请求头就可以了。而图片,文件这样的表单项,还需要设置一下Content-Type,目的是表示上传的文件类型。
写到这里,我们可以试想一下,是不是可以在安卓端“仿造”一份这样的报文内容,来进行图片的上传呢?
安卓端设置请求报文
上传部分的代码主要参考了网上大神的一些代码和视频教程,需要注意的点我都标注在代码中了。
代码如下:
public static void uploadFile(File file ,String requesturl){
String boundary = UUID.randomUUID().toString(); //通过UUID生成唯一标识符
String PREFIX = "--";
String LINE_END = "\r\n";
try{
URL url = new URL(requesturl);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(TIME_OUT);
conn.setConnectTimeout(TIME_OUT);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");//设置请求方式为POST
conn.setRequestProperty("Charset", "utf-8");//设置编码方式
conn.setRequestProperty("connection", "keep-alive");//设置持久连接
conn.setRequestProperty("Content-Type","multipart/form-data" + ";boundary =" + boundary);//这里就是在设置上文中说到的Content-Type请求头
conn.connect();
if(file != null){
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
StringBuffer sb = new StringBuffer();
/**
* 这里开始设置实体内容的格式,首先设置分隔符
*/
sb.append(PREFIX);
sb.append(boundary);
sb.append(LINE_END);
/**
* 设置Content-Disposition和Content-Type请求头,application/octet-stream是说如果不知道文件的类型,则以二进制流的形式上传下载。
* 注意回车换行也是必须与报文一致的
*/
sb.append("Content-Disposition: form-data; name=\"image\"; filename=\""+file.getName()+"\""+LINE_END);
sb.append("Content-Type: application/octet-stream; charset=utf-8" + LINE_END);
sb.append(LINE_END);
dos.write(sb.toString().getBytes());
/**
* 写入文件的二进制数据
*/
InputStream in = new FileInputStream(file);
byte[] buf = new byte[1024];
int len = -1;
while((len = in.read(buf)) != -1){
dos.write(buf,0,len);
}
in.close();
dos.write(LINE_END.getBytes());//在结束符之前,需要再添加一个回车换行
/**
* 在boundary后面加上--构成标识符,表示实体内容部分结束了
*/
dos.write((PREFIX + boundary + PREFIX + LINE_END).getBytes());
dos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
(PS:这里是Java小萌新一个,第一次写博客,主要是想把自己平时遇到的问题或者是收获,记录下来,理一理自己的思路。同时希望各位大佬指正错误!)
网友评论