JAVA使用HttpUrlConnection实现自动上传文

 

首先,实现自动上传文件方式有很多种,其中就有 SOCKET , RMI , HTTP 等,考虑到服务器本身是个网站服务器,使用SOCKET 和 RMI 需要单独开发端口, HTTP 则可以直接融合到网站中,也没有特殊的要求,所以采用了 HTTP 方式。 HTTP 方式又有好几种,其中就有 hessian 和 HttpUrlConnection 。使用 hessian 的话, hessian 提供的流上传有缺陷,可能会导致内存溢出,因此只能是将文件以多个字节数组方式传输到服务器,然后程序再整合字节成完整文件,无疑增加了代码复杂度。所以最终选择了HttpUrlConnection 。

 

通过 HttpUrlConnection 自动上传文件,服务端和用户通过网页上传文件到服务器的程序一模一样,只是客户端,我们用HttpUrlConnection 来代替浏览器向服务器提交数据。因此我们首先要弄清楚浏览器发送数据的格式。

 

第1步,数据格式:

发送文件, method 是 POST ; multipart/form-data ;我们通过 firefox 的 firebug 查看具体上传

下面数据是 iteye 上上传一个空文件是的 firebug 提交的数据。

文件格式如下:

head

 

Html代码   收藏代码
  1. Content-Length 357  
  2. Content-Type   
  3. multipart/form-data; boundary=---------------------------41184676334  

 body

Html代码   收藏代码
  1. -----------------------------41184676334   
  2. Content-Disposition: form-data; name="authenticity_token"   
  3.   
  4.   
  5. vggMNy0klrhNiSh9bQkSYeN/c3tx11I/lS0T7YDpc9U=   
  6. -----------------------------41184676334   
  7. Content-Disposition: form-data; name="attachment[uploaded_data]"filename="test.zip" Content-Type: application/zip  
  8.   
  9.   
  10.  -----------------------------41184676334—  

 

 

格式解析:

 

Content-Length 定义了发送数据的总字节数;

Content-Type 定义格式和数据分界符 boundary ,下面发送的数据将用这个 boundary 分隔每一个变量, boundary 中的41184676334 是由浏览器随机生成,我们可以直接使用 。

发送 2 个变量,分别是 authenticity_token 和空文件 test.zip

变量开头是 “--”+boundary ,然后下一行 Content-Disposition 定义变量名称,下一行是 content-type 定义数据格式,这个不是必须的,发送文件数据时, content-type 需要指定,

这里指出了文件类型,我们可以用 application/octet-stream 告诉服务器发送的是流,再空两行(即 \r\n\r\n ),是变量的值或者文件的内容。然后下一行开始是另外一个变量。最后一个变量以 “—“+boundary+”—“ 结束。

 

第2步 HTTPS 处理

有时候网站采用的是 HTTPS 协议,因此我们需要相应的证书,我们考虑是让程序接受所有证书,就像浏览器上设置接受所有证书,不管签名与否。实际是我们也无需证书,服务器也是我们自己的,我当然相信自己编写的客户端当然也相信自己的服务端了。

 

 

要接受所有服务器上的证书,我们需要实现两个接口

javax.net.ssl.X509TrustManager 和 javax.net.ssl.HostnameVerifier

接口中的函数都以空函数覆盖即可。其中 javax.net.ssl.HostnameVerifier 的 verify 返回 true 即可。下面是我们连接服务器的函数

 

 

Java代码   收藏代码
  1. HttpURLConnection getHttpConnection(String urlString) throws Exception  
  2.     {  
  3.         URL url = new URL(urlString);  
  4.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  5.         if ("https".equalsIgnoreCase(url.getProtocol()))      
  6.         {  
  7.             HttpsURLConnection httpsConn=(HttpsURLConnection) conn;  
  8.             TrustManager[] managers ={new MyX509TrustManager()};  
  9.             SSLContext sslContext=SSLContext.getInstance("TLS");  
  10.             sslContext.init(null, managers, new SecureRandom());  
  11.             SSLSocketFactory ssf=sslContext.getSocketFactory();  
  12.             httpsConn.setSSLSocketFactory(ssf);  
  13.             httpsConn.setHostnameVerifier(new MyHostnameVerifier());  
  14.             return httpsConn;  
  15.         }  
  16.         else  
  17.         {  
  18.             return conn;  
  19.         }  
  20.     }  

 

其中 MyX509TrustManager 和 MyHostnameVerifier 分别是

javax.net.ssl.X509TrustManager 和 javax.net.ssl.HostnameVerifier 的实现类。

 

 

第 3 步,发送数据

连接了服务器,就可以发送数据了。

首先定义连接的 header 和连接方式和 boundary

Java代码   收藏代码
  1. conn = getHttpConnection(urlString);  
  2. conn.setDoOutput(true);  
  3. conn.setDoInput(true);  
  4. conn.setRequestMethod("POST");  
  5. String BOUNDARY = "---------------------------41184676334";  
  6.   
  7. conn.setRequestProperty("connection""Keep-Alive");  
  8. conn.setRequestProperty("Charsert""UTF-8");  
  9. conn.setRequestProperty("user-agent",  
  10.                     "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0");                        //可以不指定  
  11. conn.setRequestProperty("Content-Type",  
  12.                     "multipart/form-data; boundary=" + BOUNDARY);  
  13. conn.setRequestProperty("Content-Length",  
  14.                     String.valueOf(contentLen));  //不清楚长度,可以不写  
  15.               
  16. conn.setAllowUserInteraction(false);    //无需用户交互,即弹出https等的对话框。  
  17. conn.setChunkedStreamingMode(blockSize);   //告诉HttpUrlConnection,我们需要采用流方式上传数据,无需本地缓存数据。HttpUrlConnection默认是将所有数据读到本地缓存,然后再发送给服务器,这样上传大文件时就会导致内存溢出。  
  18.   
  19. byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();  
  20. StringBuffer sb = new StringBuffer();  
  21.   
  22. sb.append("--").append(BOUNDARY).append("\r\n");  
  23. sb.append("Content-Disposition: form-data; name=\"username\"\r\n\r\n");  
  24. sb.append(username);  
  25. sb.append("\r\n--").append(BOUNDARY).append("\r\n");  
  26.   
  27. sb.append("--").append(BOUNDARY).append("\r\n");  
  28. sb.append("Content-Disposition: form-data; name=\"password\"\r\n\r\n");  
  29. sb.append(password);  
  30. sb.append("\r\n--").append(BOUNDARY).append("\r\n");  
  31.   
  32. sb.append("--").append(BOUNDARY).append("\r\n");  
  33. sb.append("Content-Disposition: form-data; name=\"file\"; filename=\identify.zip\"\r\n");  
  34. sb.append("Content-Type: application/octet-stream\r\n\r\n");  
  35.   
  36. byte[] data = sb.toString().getBytes();  
  37. long fLen = f.length();  
  38. long contentLen = data.length + fLen + end_data.length;  
  39. os.write(data);  //发送非文件数据  
  40.               
  41. fis = new FileInputStream(f);  //读取文件内容,发送数据,数据要一点点发送,不能一下全部读取发送,否则会内存溢出。  
  42. int rn;  
  43. byte[] buf = new byte[blockSize];    
  44. while ((rn = fis.read(buf, 0, blockSize)) > 0) {  
  45.     os.write(buf, 0, rn);  
  46. }  
  47. os.write(end_data);  
  48. os.flush();  
  49. os.close();  
  50. fis.close();  

  第 4 步,接受服务器处理结果

Java代码   收藏代码
  1. ByteArrayOutputStream bo = new ByteArrayOutputStream();  
  2. InputStream is = conn.getInputStream();  
  3. byte[] inbuf = new byte[blockSize/10];  
  4. while ((rn = is.read(inbuf, 0, blockSize/10)) > 0) {  
  5.                 bo.write(inbuf);  
  6. }  
  7. is.close();  
  8. String ret = bo.toString();  
  9. bo.close();  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值