美文网首页
如何从客户端上传图片到服务器

如何从客户端上传图片到服务器

作者: 表总是背影 | 来源:发表于2018-03-17 19:23 被阅读0次

最近在做项目的过程中,遇到了一个问题,就是如何从安卓端将图片上传到服务器。通过查阅资料后,在此将自己的收获整理总结一下。

HTTP报文的内容

在Web应用程序中,HTTP协议充当了信使的角色。客户端向服务器发起HTTP请求,服务器接收到请求后将所请求的数据写入HTTP响应报文中,再回送给客户端。那么,当向服务器上传一张图片时,HTTP报文是如何将图片“带给”服务器的呢?
首先,我们通过网页表单向服务器发送图片,来看一看HTTP报文的具体内容是什么.
这里我写了一个简单的登录表单:


输入相关数据,点击登录。

通过抓包工具,看一下HTTP报文的内容:

一个完整的HTTP请求包含如下内容:一个请求行,若干请求头,以及实体内容。这里我们主要关注一下请求头和实体内容部分。

在Request Payload中可以看到,实体内容里包含了三部分内容:输入的用户名,密码,以及上传图片的二进制数据。不难发现,它们之间是通过这样一串字符来进行分隔的: 这段字符串的作用正是用来标明一段内容的开始。也就是说,通过它,我们可以将表单中提交的数据分隔开。用户名是用户名部分,图片数据是图片数据部分。那么这段字符串是如何进行设置的呢?这样的实体内容又是如何设置的呢?
我们看一下请求头中的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小萌新一个,第一次写博客,主要是想把自己平时遇到的问题或者是收获,记录下来,理一理自己的思路。同时希望各位大佬指正错误!)

相关文章

网友评论

      本文标题:如何从客户端上传图片到服务器

      本文链接:https://www.haomeiwen.com/subject/mehjqftx.html