博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中HttpURLConnection网络请求
阅读量:6453 次
发布时间:2019-06-23

本文共 10948 字,大约阅读时间需要 36 分钟。

hot3.png

HTTP网络请求中的GET,POST,PUT,DELETE就对应着查,改,增,删4个操作,而一般用的的是GET和POST。

1.GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连.如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
GET方式提交的数据受浏览器及服务器对URL长度的限制。
可以使用GET方式提交数据流,获取数据流或下载文件。

2.POST把提交的数据放置在是HTTP包的包体中,必须要到FORM(表单)。

POST方式提交的数据受服务器对表单处理能力的限制。
可以用POST方式提交数据流或文件,获取数据流。

 

这里介绍的HttpURLConnection,是java的标准类, 在Android2.3版本及以后,HttpURLConnection是最佳的选择。它的API简单,体积较小。默认带gzip压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。

 * 注意:在Android2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug,建议用HttpClient。 此外,不建议上传大文件,如果要上传大文件,建议用HttpClient。

 

HttpURLConnection在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重:

对connection对象的一切配置(那一堆set函数)都必须要在connect()之前完成,如果没有connect(),则必须在getInputStream()之前完成。
而getOutputStream().write()上传参数或上传文件必须在getInputStream()之前完成。

也就是说,getInputStream()以后,请求已经发送出去了,所有关于请求的配置都要在此前完成,该函数的返回流已经是服务器的反馈了。

public class HttpURLConnectionUtil { public static final int READ_TIMEOUT = 30*1000; public static final int CONNECT_TIMEOUT = 10*1000; public static final int EXCEPTION_ERR = 888; // 文件下载的状态 public static final int DOWNLOAD_FAIL = -1;  //下载失败 public static final int DOWNLOAD_PART = 0;  //下载了一部分 public static final int DOWNLOAD_COMPLETE = 1;  //完全下载  /**  * 采用POST方式提交数据流  * POST把提交的数据放置在是HTTP包的包体中,必须要到FORM(表单)。  * POST方式提交的数据受服务器对表单处理能力的限制。此方法不支持提交大文件  * @param handler  *             用消息发送机制返回HTTP Response结果  * @param urlStr  *             链接  * @param params  *             提交到服务器的参数  * */ public static void postWithHttpURLConnection(final Handler handler, final String urlStr,   final Map
 params){  StringBuffer data = new StringBuffer();  Message msg = handler.obtainMessage();      HttpURLConnection conn = null;  InputStream is = null;  OutputStream os = null;  try {   /* 发送HTTP请求前的Request部分   */   URL url = new URL(urlStr);   conn = (HttpURLConnection) url.openConnection();   conn.setConnectTimeout(CONNECT_TIMEOUT);   conn.setReadTimeout(READ_TIMEOUT);   conn.setRequestMethod("POST");   // 设置是否向connection输出,因为这个是post请求,参数要放在http正文内,因此需要设为true   conn.setDoOutput(true);   // 要读取http的反馈,因此需要设为true   conn.setDoInput(true);   // 说明正文是urlencoded编码过的form参数,同时我们对参数要进行UTF_8 转码成byte字节流   conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");   // Post 请求不能使用缓存   conn.setUseCaches(false);   conn.setInstanceFollowRedirects(true);      // 正文的内容是通过outputStream流写入   if( params != null ) {    StringBuffer param = new StringBuffer();    int index = 0;    for (Map.Entry
 entry : params.entrySet()) {     String key = entry.getKey();     String value = entry.getValue();     if( index > 0 ){      param.append("&");     }     param.append(key);     param.append("=");     param.append(value);     index += 1;    }    if(param.length() > 0) {     os = conn.getOutputStream();     // 这种格式数据value先进行UTF_8 转码成byte字节流     os.write(param.toString().getBytes("UTF_8"));    }   }   /* Request部分配置完成 */          /* 发送HTTP请求后的Response部分 */   int responseCode = conn.getResponseCode();   is = conn.getInputStream();   if ( is != null ) {    int readSize = 0;    byte[] buffer = new byte[1024];    while( ( readSize = is.read(buffer) ) != -1 ) {     //将流字节通过UTF-8转码成字符串     String str = new String(buffer,"UTF_8");     data.append(str);    }   }   String json = data.toString();   msg.what = responseCode;   msg.obj = json;  } catch (Exception e) {   msg.what = EXCEPTION_ERR;   msg.obj = e.getMessage();  } finally {   // 不管是否发生异常,都会调用的代码段   msg.sendToTarget();   if (os!=null){    try {     os.close();    } catch (IOException e) {      e.printStackTrace();    }   }   if (is!=null){    try {     is.close();    } catch (IOException e) {     e.printStackTrace();    }   }   if (conn!=null){    conn.disconnect();   }  } }  /**  * 采用GET方式请求数据流  * GET提交的数据显示放置在HTTP协议头中,以?分割URL和传输数据,参数之间以&相连.  * GET提交的数据受浏览器及服务器对URL长度的限制,一般是1024字节。  * @param handler  *             用消息发送机制返回HTTP Response结果  * @param urlStr  *             链接  * */ public static void getWithHttpURLConnection(final Handler handler, final String urlStr){  StringBuffer data = new StringBuffer();  Message msg = handler.obtainMessage();  HttpURLConnection conn = null;  InputStream is = null;  try {   URL url = new URL(urlStr);   conn = (HttpURLConnection) url.openConnection();   conn.setConnectTimeout(CONNECT_TIMEOUT);   conn.setReadTimeout(READ_TIMEOUT);   conn.setRequestMethod("GET");         int responseCode = conn.getResponseCode();   is = conn.getInputStream();   if( is != null ) {    int readSize = 0;    byte[] buffer = new byte[1024];    is = conn.getInputStream();    while( ( readSize = is.read(buffer) ) != -1 ) {     //将流字节通过UTF-8转码成字符串     String str = new String(buffer,"UTF_8");     data.append(str);    }   }   msg.what = responseCode;   msg.obj = data.toString();  } catch (Exception e) {   msg.what = EXCEPTION_ERR;   msg.obj = e.getMessage();  } finally {   msg.sendToTarget();   if (conn!=null){    conn.disconnect();   }   if (is!=null){    try {     is.close();    } catch (IOException e) {     e.printStackTrace();    }   }  } }  /**  * 使用GET的方法下载大文件,可以支持断点续传。下载完的文件保存在用户定义的指定位置。  *   * @param handler  *             与主线程的交互,返回下载结果状态  * @param urlStr  *     下载链接  * @param filePath  *     下载文件保存路径  * @param fileName  *     下载文件的文件名  * */ public static void downloadFileWithHttpURLConnection(final Handler handler, final String urlStr,    final String filePath, final String fileName) {  DownloadFileInfo fileInfo = new DownloadFileInfo(urlStr,filePath,fileName);  int status = downloadWithHttpURLConnection(fileInfo);  if( status == DOWNLOAD_PART ) {   if( shouldRangeDownload(fileInfo) ) {    status = downloadRangeWithHttpURLConnection(fileInfo);   }  }  Message msg = handler.obtainMessage();  msg.what = status;  msg.obj = "";  handler.sendMessage(msg); }  /**  * 判断是否可以断点续传  *   * @param DownloadFileInfo 保存下载信息:  *    mURL:下载链接  *    mFilePath:指定下载文件保存路径  *    mFileName:下载文件的文件名  *    mCompleteFileLength:待下载文件的Size  *    mCurrentFileLength:已经下载的文件的Size,用于断点续传  *    mEtag:服务器为某个文件生产的唯一标识值,每次文件有更新该值就会变化。  * */ private static boolean shouldRangeDownload(DownloadFileInfo fileInfo){  File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);  if(!file.exists()){   // 原来下载的文件已经被删除了,重新下载   fileInfo.clearFileSizeRecord();   return false;  }    HttpURLConnection conn = null;  try {   URL url = new URL(fileInfo.mURL);   conn = (HttpURLConnection) url.openConnection();   conn.setConnectTimeout(CONNECT_TIMEOUT);   conn.setRequestMethod("GET");      String acceptRange= conn.getHeaderField("Accept-Ranges");   String etag = conn.getHeaderField("ETag");   if( acceptRange!=null && acceptRange.equalsIgnoreCase("bytes") &&     fileInfo.mEtag!=null && etag!=null && etag.equalsIgnoreCase( fileInfo.mEtag )) {    return true;   } else {    // 1. 服务器不支持断点续传    // 2. ETag改变了    // 应该重新下载整个文件    return false;   }     } catch (Exception e) {   return false;  } finally {   if (conn!=null){    conn.disconnect();   }  } } /**  * 一次性全部下载  * 1. 不要设置ReadTimeOut,如果要设置,最好时间长一些,因为大文件的下载本来就耗时  * 2. 下载过程采用一边读输入流,一边写入文件的方法,节约内存  * 3. 如果只下载了一部分就被中断,但是服务器不支持断点续传的话,必须重新下载  */ public static int downloadWithHttpURLConnection(DownloadFileInfo fileInfo) {  HttpURLConnection conn = null;  InputStream is = null;  RandomAccessFile savedfile = null;  try {   URL url = new URL(fileInfo.mURL);   conn = (HttpURLConnection) url.openConnection();   conn.setConnectTimeout(CONNECT_TIMEOUT);   conn.setRequestMethod("GET");   //保存文件的标示   String etag = conn.getHeaderField("ETag");   if(etag!=null){    fileInfo.mEtag = etag;   }      //新建需要写入的RandomAccessFile   File dir = new File(fileInfo.mFilePath);   if(!dir.exists()){    dir.mkdirs();   }   File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);   if(!file.exists()){    file.createNewFile();   }   savedfile = new RandomAccessFile(file,"rwd");      int responseCode = conn.getResponseCode();   if ( responseCode == 200 ) {//用来表示请求成功.    int len = conn.getContentLength();    if( len <= 0 ) {     return DOWNLOAD_FAIL;    }    fileInfo.mCompleteFileLength = len;        int readSize = 0;    byte[] buffer = new byte[1024];//1k内存    is = conn.getInputStream();    while( ( readSize = is.read(buffer) ) != -1 ) {     // 循环从输入流中读1k数据,写入文件     savedfile.write(buffer, 0, readSize);     fileInfo.mCurrentFileLength += readSize;    }   } else {    return DOWNLOAD_FAIL;   }   int status = DOWNLOAD_FAIL;   if( fileInfo.mCurrentFileLength > 0 ) {    if( fileInfo.mCurrentFileLength == fileInfo.mCompleteFileLength ) {     status = DOWNLOAD_COMPLETE;    } else {     status = DOWNLOAD_PART;    }   }   return status;  } catch (Exception e) {   int status = DOWNLOAD_FAIL;   if( fileInfo.mCurrentFileLength > 0 ) {    status = DOWNLOAD_PART;   }   return status;  } finally {   if( conn != null ) {    conn.disconnect();   }   if( is != null ) {    try {     is.close();    } catch (IOException e) {     e.printStackTrace();    }   }   if( savedfile != null ) {    try {     savedfile.close();    } catch (IOException e) {     e.printStackTrace();    }   }  } }  /**   * 断点续传下载  * 注意:断点续传成功的getResponseCode()是206,不是200  */ public static int downloadRangeWithHttpURLConnection(DownloadFileInfo fileInfo) {  HttpURLConnection conn = null;  InputStream is = null;  RandomAccessFile savedfile = null;  try {   URL url = new URL(fileInfo.mURL);   conn = (HttpURLConnection) url.openConnection();   conn.setConnectTimeout(CONNECT_TIMEOUT);   conn.setRequestMethod("GET");      int startPos = fileInfo.mCurrentFileLength;//开始位置   conn.setRequestProperty("Range", "bytes=" + startPos + "-");//设置获取实体数据的范围            conn.connect();               //新建需要写入的RandomAccessFile   File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);   savedfile = new RandomAccessFile(file,"rwd");   savedfile.seek(startPos);       int responseCode = conn.getResponseCode();   if ( responseCode == 206 ) {//断点续传成功的反馈值是206,不是200    int len = conn.getContentLength();    if( len <= 0 ) {     return DOWNLOAD_FAIL;    }        byte[] buffer = new byte[1024];    int readSize = 0;    is = conn.getInputStream();    while( (readSize=is.read(buffer)) != -1 ) {     savedfile.write(buffer, 0, readSize);     fileInfo.mCurrentFileLength += readSize;    }   } else {    return DOWNLOAD_FAIL;   }   int status = DOWNLOAD_FAIL;   if( fileInfo.mCurrentFileLength > 0 ) {    if( fileInfo.mCurrentFileLength == fileInfo.mCompleteFileLength ) {     status = DOWNLOAD_COMPLETE;    } else {     status = DOWNLOAD_PART;    }   }   return status;  } catch (Exception e) {   int status = DOWNLOAD_FAIL;   if( fileInfo.mCurrentFileLength > 0 ) {    status = DOWNLOAD_PART;   }   return status;  } finally {   if (conn!=null){    conn.disconnect();   }   if(is!=null){    try {     is.close();    } catch (IOException e) {     e.printStackTrace();    }   }   if(savedfile!=null){    try {     savedfile.close();    } catch (IOException e) {     e.printStackTrace();    }   }  } }}

 

 

转载于:https://my.oschina.net/u/1984976/blog/374873

你可能感兴趣的文章
js滚动加载到底部
查看>>
关于mac远程链接window服务器以及实现共享文件
查看>>
Redis慢查询,redis-cli,redis-benchmark,info
查看>>
Virtualbox 虚拟机网络不通
查看>>
java概念基础笔记整理
查看>>
self parent $this关键字分析--PHP
查看>>
CC_UNUSED_PARAM 宏含义的解释
查看>>
leetcode124二叉树最大路径和
查看>>
AngularJS笔记整理 内置指令与自定义指令
查看>>
学习OpenCV——BOW特征提取函数(特征点篇)
查看>>
shell与正则表达式
查看>>
第三篇:白话tornado源码之请求来了
查看>>
10分钟搞定支付宝和微信支付的各种填坑
查看>>
表示数值的字符串
查看>>
JQUERY AJAX请求
查看>>
html css 伪样式
查看>>
超级账本Fabric区块链用弹珠游戏Marbles 部署
查看>>
Maven多模块项目
查看>>
Oracle、PostgreSQL与Mysql数据写入性能对比
查看>>
整理Java基础知识--选择与判断
查看>>