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

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

作者: 表总是背影 | 来源:发表于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