先看下一开始使用的网络框架核心代码:

private Message doPost(final String url, final Map<String, String> params, final Map<String, InputStream> inputStreams,final InterCallback callback) {long startTime = System.currentTimeMillis();Message message=new Message();String BOUNDARY = java.util.UUID.randomUUID().toString();String PREFIX = "--", LINEND = "\r\n";String CHARSET = XHConf.in().net_encode;HttpURLConnection conn=null;try {
//          if(url.indexOf("Upload/imgs")>-1) Thread.sleep(130*1000);URL uri = new URL(url);conn = (HttpURLConnection) uri.openConnection();conn.setDoInput(true);// 允许输入conn.setDoOutput(true);// 允许输出conn.setUseCaches(false);conn.setRequestMethod("POST"); // Post方式conn.setConnectTimeout(XHConf.in().net_timeout*2);conn.setReadTimeout(XHConf.in().net_timeout * 10);//设置headerMap<String,String> header = callback.getReqHeader(new HashMap<String, String>(),url,params);UtilLog.print(XHConf.in().log_tag_net,"d","------------------REQ_POST------------------\n"+url+"\n"+params+";"+inputStreams+"\nheader:"+header.toString());for (Map.Entry<String, String> map : header.entrySet()) {conn.setRequestProperty(map.getKey(), map.getValue());}// 首先组拼文本类型的参数StringBuilder sb = new StringBuilder();if(inputStreams.isEmpty()){for (Map.Entry<String, String> entry : params.entrySet()) {sb.append(entry.getKey() + "=" +  URLEncoder.encode(entry.getValue(),XHConf.in().net_encode) + "&");}if(sb.length() > 1)sb.deleteCharAt(sb.length()-1);conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");}else{for (Map.Entry<String, String> entry : params.entrySet()) {sb.append(PREFIX);sb.append(BOUNDARY);sb.append(LINEND);sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND);sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND);sb.append("Content-Transfer-Encoding: 8bit" + LINEND);sb.append(LINEND);sb.append(entry.getValue());sb.append(LINEND);}conn.setRequestProperty("Content-Type", "multipart/form-data" + ";boundary=" + BOUNDARY);}DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());outStream.write(sb.toString().getBytes());// 发送文件数据if (!inputStreams.isEmpty()){for (Map.Entry<String, InputStream> iss : inputStreams.entrySet()) {StringBuilder sb1 = new StringBuilder();sb1.append(PREFIX);sb1.append(BOUNDARY);sb1.append(LINEND);//组装文件流数据String[] fileNameSplit = iss.getKey().split("_");String contentType = fileNameSplit[fileNameSplit.length - 1];StringBuilder fileName = new StringBuilder();if(fileNameSplit.length<3) throw new Exception("文件流的key用_无法切割:"+iss.getKey());for(int i = 1; i < fileNameSplit.length - 1; i++){fileName.append(fileNameSplit[i]);}sb1.append("Content-Disposition: form-data; name=\"" + fileNameSplit[0] + "[]\"; filename=\""+ fileName.toString() + "\"" + LINEND);sb1.append("Content-Type: "+contentType+"; charset=" + CHARSET + LINEND);sb1.append(LINEND);outStream.write(sb1.toString().getBytes());InputStream is = iss.getValue();byte[] buffer = new byte[1024];int len = 0;while (is != null && (len = is.read(buffer)) != -1) {outStream.write(buffer, 0, len);}outStream.write(LINEND.getBytes());}// 请求结束标志byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();outStream.write(end_data);}outStream.flush();outStream.close();// 得到响应int resState = conn.getResponseCode();if (resState == 200) {Map<String, List<String>> ml = conn.getHeaderFields();if(ml.containsKey("Set-Cookie")){Map<String,String> map = getPostCookieMap(ml.get("Set-Cookie"));callback.saveCookie(map,url,"doPost");}message.what=REQ_OK_STRING;message.obj=UtilString.inputStream2String(conn.getInputStream(), XHConf.in().net_encode);} else {message.what=REQ_STATE_ERROR;message.obj=resState;}} catch (Exception e) {message.what=REQ_EXP;message.obj=e;}callback.requestTime=System.currentTimeMillis()-startTime;if(conn!=null) conn.disconnect();return message;}

很简单能看出,这是用的自己拼接http header和body,然后通过安卓原生最基础的网络类HttpURLConnection或DefaultHttpClient这之类的来实现。后来发现上传图片的时候总会出现图片颜色混乱花图、图片出现半张图等现象。于是做了如下改动:

private Message doPost(final String url, final Map<String, String> params, final Map<String, InputStream> inputStreams,final InterCallback callback) {long startTime = System.currentTimeMillis();Message message=new Message();//准备链接HttpParams httpParameters = new BasicHttpParams();HttpConnectionParams.setConnectionTimeout(httpParameters, XHConf.in().net_timeout*2);HttpConnectionParams.setSoTimeout(httpParameters, XHConf.in().net_timeout*10);DefaultHttpClient client = new DefaultHttpClient(httpParameters);HttpPost post = new HttpPost(url);Map<String,String> header = callback.getReqHeader(new HashMap<String, String>(),url,params);for (Map.Entry<String, String> map : header.entrySet()) {post.setHeader(map.getKey(), map.getValue());}UtilLog.print(XHConf.in().log_tag_net,"d","------------------REQ_POST------------------\n"+url+"\n"+params+";"+inputStreams+"\nheader:"+header.toString());try {//设置参数if(inputStreams.isEmpty()){ArrayList<NameValuePair> postEntry=new ArrayList<NameValuePair>();for (Map.Entry<String, String> entry : params.entrySet()) {postEntry.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));}post.setEntity(new UrlEncodedFormEntity(postEntry,XHConf.in().net_encode));}else{MultipartEntity multipartEntity = new MultipartEntity();for (Map.Entry<String, String> entry : params.entrySet()) {StringBody sb = new StringBody(entry.getValue(),Charset.forName(XHConf.in().net_encode));multipartEntity.addPart(entry.getKey(), sb);}for (Map.Entry<String, InputStream> entry : inputStreams.entrySet()) {//组装文件流数据String[] fileNameSplit = entry.getKey().split("_");
//                  String contentType = fileNameSplit[fileNameSplit.length - 1];StringBuilder fileName = new StringBuilder();if(fileNameSplit.length<3) throw new Exception("文件流的key用_无法切割:"+entry.getKey());for(int i = 1; i < fileNameSplit.length - 1; i++){fileName.append(fileNameSplit[i]);}InputStreamBody isb = new InputStreamBody(entry.getValue(), fileName.toString());multipartEntity.addPart(fileNameSplit[0] + "[]", isb);}post.setEntity(multipartEntity);}HttpResponse response = client.execute(post);int resState=response.getStatusLine().getStatusCode();if (resState == HttpURLConnection.HTTP_OK) {message.what=REQ_OK_STRING;message.obj=UtilString.inputStream2String(response.getEntity().getContent(), XHConf.in().net_encode);callback.saveCookie(getGetCookieMap(client.getCookieStore().getCookies()),url,"doPost");} else {message.what=REQ_STATE_ERROR;message.obj=resState;}} catch (Exception e) {message.what=REQ_EXP;message.obj=e;}callback.requestTime=System.currentTimeMillis()-startTime;client.getConnectionManager().shutdown();return message;}

至此,使用的是httpmime-4.1.3.jar包中的MultipartEntity然后通过HttpPost来进行上传,用了框架之后的好处是基本上遇不到上传图片变花的问题了,但半张图的问题仍然存在,最关键的是引入了上传图片文件服务器返回诡异的411错误,仅少部分手机会出现,而且是必然。这个在stackoverflow也有提出,不过一直没啥好的解法  http://stackoverflow.com/questions/15552276/answer/submit

进过测试发现,普通web服务器是完全没问题的,但我服务器是通过负载均衡来进行了一次转发,大概也就是在这个过程丢失了contentLength,系统也没按照content chunk读取不定长请求。第一反应是手动设置length参数,显然是错的了。

进过分析,很可能是inputStream流长度无法读取,所以contentLength消失。另外直接用流上传可能存在流中数据中断或异常,导致图片变画或只有一半。后来进一步研究才发现了MultipartEntity已经不提倡使用了,在新版的httpmime中要使用MultipartEntityBuilder。详见:http://www.2cto.com/kf/201402/276505.html

修改如下:

private Message doPost(String url, Map<String, String> params, Map<String, byte[]> byteMap, InterCallback callback) {long startTime = System.currentTimeMillis();Message message=new Message();//准备连接HttpParams httpParameters = new BasicHttpParams();HttpConnectionParams.setConnectionTimeout(httpParameters, XHConf.in().net_timeout*2);HttpConnectionParams.setSoTimeout(httpParameters, XHConf.in().net_timeout*10);DefaultHttpClient client = new DefaultHttpClient(httpParameters);Map<String,String> header = callback.getReqHeader(new HashMap<String, String>(),url,params);header=changeHeader(url,header);UtilLog.print(XHConf.in().log_tag_net,"d","------------------REQ_POST------------------\n"+url+"\n"+params+";"+byteMap+"\nheader:"+header.toString());HttpPost post = new HttpPost(changeUrlFromHeader(url, header));for (Map.Entry<String, String> map : header.entrySet()) {post.addHeader(map.getKey(), map.getValue());}try {//设置参数if(byteMap.isEmpty()){ArrayList<NameValuePair> postEntry=new ArrayList<NameValuePair>();for (Map.Entry<String, String> entry : params.entrySet()) {postEntry.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));}post.setEntity(new UrlEncodedFormEntity(postEntry,XHConf.in().net_encode));}else{Charset charset=Charset.forName(XHConf.in().net_encode);MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);multipartEntityBuilder.setCharset(charset);for (Map.Entry<String, String> entry : params.entrySet()) {multipartEntityBuilder.addTextBody(entry.getKey(),entry.getValue(),ContentType.create("text/plain",charset));}for (Map.Entry<String, byte[]> entry : byteMap.entrySet()) {//组装文件流数据String[] fileNameSplit = entry.getKey().split("_");String contentType = fileNameSplit[fileNameSplit.length - 1];StringBuilder fileName = new StringBuilder();if(fileNameSplit.length<3) throw new Exception("文件流的key用_无法切割:"+entry.getKey());for(int i = 1; i < fileNameSplit.length - 1; i++){fileName.append(fileNameSplit[i]);}multipartEntityBuilder.addBinaryBody(fileNameSplit[0] + "[]", entry.getValue(), ContentType.create(contentType), fileName.toString());}post.setEntity(multipartEntityBuilder.build());}HttpResponse response = client.execute(post);int resState=response.getStatusLine().getStatusCode();if (resState == HttpURLConnection.HTTP_OK) {message.what=REQ_OK_STRING;message.obj=UtilString.inputStream2String(response.getEntity().getContent(), XHConf.in().net_encode);callback.saveCookie(getGetCookieMap(client.getCookieStore().getCookies()),url,"doPost");} else {message.what=REQ_STATE_ERROR;message.obj=resState;}} catch (Exception e) {message.what=REQ_EXP;message.obj=e;}callback.requestTime=System.currentTimeMillis()-startTime;client.getConnectionManager().shutdown();return message;}

注意这里用的是addBinaryBody的byte[]方法,而不是直接传inputStream,果然content-length属性已经明显出来了,但此种方法用的自然不是content chunk读取不定长的方式。不过至此网络底层的问题也基本解决啦。留下来给自己做个历史。

安卓网络框架,上传图片花图,上传状态411被服务器驳回相关推荐

  1. 小程序多图上传至阿里云云服务器

    1.小程序端点击上传图片完成时触发 onChangeTap:function(env){ //获得图片信息 var Photo=this.data.photo //循环所有图片数据 env.detai ...

  2. 安卓微信浏览器无法支持input multiple的h5属性多图上传

    H5手机端 实现多图上传的功能 但是实际上 安卓手机上只能义词上传一张图片(测试的机型:小米)代码如下: 在微信开发中遇见一个问题 应用上传插件安卓手机无法进行多张上传 当时现象: 微信浏览器选择安卓 ...

  3. 微信公众号开发JSSDK上传图片(多图上传)

    前面做了微信公众号开发,涉及到了图片上传功能.微信jssdk-api带有一套完整的调用选择本地图片上传的功能,很多朋友在问到多图上传的问题.在这里分享一下自己的做法,其实并不是自己的做法,就是完全按照 ...

  4. vant weapp 多选上传图片_微信小程序结合vant weapp ui实现多图上传组件

    微信小程序多图上传 最近在写小程序的商品上传,为方便需要使用多张图片的上传的功能.因为小程序不支持数组的多张图片同时上传,然后根据自己的需求创建了一个组件希望能够帮到大家 效果图 创建一个图片上传的p ...

  5. java struts2 上传图片_Java框架Struts2实现图片上传功能

    Struts 2 框架为处理文件上传提供了内置支持,它使用"在 HTML 中基于表单的文件上传".当上传一个文件时,它通常会被存储在一个临时目录中,而且它们应该由 Action 类 ...

  6. Bootstrap+PHP实现多图上传

    插件及源代码可以在这里下载 http://www.jq22.com/jquery-info5231 下面是根据下载的demo进行补充: 使用bootstrap界面美观,可预览,可拖拽上传,可配合aja ...

  7. java多图片上传json_[Java教程]SpringMVC框架五:图片上传与JSON交互

    [Java教程]SpringMVC框架五:图片上传与JSON交互 0 2018-08-07 22:00:42 在正式图片上传之前,先处理一个细节问题: 每一次发布项目,Tomcat都会重新解压war包 ...

  8. Bootstrap+PHP fileinput 实现多图上传 这是ajax上传,只能单张单张图片地上传

    插件及源代码可以在这里下载 http://www.jq22.com/jquery-info5231 下面是根据下载的demo进行补充: 使用bootstrap界面美观,可预览,可拖拽上传,可配合aja ...

  9. SSM框架+Plupload实现分块上传(Spring+SpringMVC+MyBatis+Plupload)

    关于Plupload的介绍,相信它的官网http://www.plupload.com/已经给得很详细了.Plupload的上传原理简单点说,就是将用户选中的文件(可多个)分隔成一个个小块,依次向服务 ...

最新文章

  1. 2月国内搜索市场:360继续上升 百度下降0.62%
  2. Zookeeper源码分析:Leader角色初始化
  3. mysql 唯一索引_MySQL学会用索引,让你数据库的查询速度起飞
  4. 哭了,复现TensorFlow版本MAE的shuffle和reshuffle
  5. 金融专有云数据安全实践
  6. Java 并发工具箱之concurrent包
  7. (十)python3 只需3小时带你轻松入门——模块与包
  8. solidworks属性管理器_老式经典|如何提高SOLIDWORKS的运行速度
  9. 多区域OSPF基本配置
  10. 判断是否为一棵树的子树 Subtree of Another Tree
  11. vecm模型怎么写系数_时变秩和时变系数VECM模型与“费雪效应”机制检验
  12. Unity 导入原神人物模型
  13. 面向对象编程思想详解汇总
  14. IOI国家集训队历年论文
  15. 课程回顾丨基于FPGA的OFDM可见光通信系统实现
  16. 路由器与无线网如何连接到服务器,两个路由器无线连接怎么设置_如何将两个路由器无线连接-192路由网...
  17. python项目二:多种验证码及二维码输出
  18. 凌晨4点的中国人都在干什么?这份数据可视化地图给你答案
  19. 基于低加密指数广播攻击(Hastad攻击)的更深一步学习
  20. Nginx 源码分析

热门文章

  1. python爬取YB视频评论
  2. 全国号码段归属地文件数据
  3. 人活着是为了什么(转载)
  4. ireport报表分页导致多一张空白页
  5. 程序员必备的软技能-《如何阅读一本书》
  6. 团体程序设计天梯赛-练习集-L1区001——048C语言全解
  7. [CISCN2019 华北赛区 Day1 Web5]CyberPunk
  8. 快改图工具可在线批量压缩
  9. 中谷教育python精讲_中谷教育Python视频教程
  10. 几种换肤软件使用问题