Android利用HttpURLConnection发送Http请求上传文件
关于Android或Java的Http get,post请求的例子和做法还是很多的,本人在项目中没有使用第三方的类库,利用了Android原生类库HttpURLConnection做了一次文件上传,代码逻辑不复杂,就是要理解Http协议的过程和耐心+细心的调试:下面是一个实战例子,测试成功:
如需了解Http文件上传中Http 协议的原理:请参考本人的另外一篇文章:
从HTTP的multipart/form-data分析看C#后台 HttpWebRequest文件上传
https://blog.csdn.net/elie_yang/article/details/80710059
这里再写一个Java版本的文件上传:
public static String upload(String uploadUrl,String fileName, Map map, byte[] bytesData) { try { final String newLine = "\r\n"; // 换行符 final String boundaryPrefix = "--"; //边界前缀 // 定义数据分隔线 final String boundary = String.format("=========%s",System.currentTimeMillis()); URL url = new URL(uploadUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求头参数 conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("Charsert", "UTF-8"); conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); OutputStream out = new DataOutputStream(conn.getOutputStream()); String keyValue = "Content-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n"; byte[] parameterLine= (boundaryPrefix+boundary+newLine).getBytes(); //构建请求参数 if(map!=null&&map.size()>0){ for (Entry e : map.entrySet()) { byte[] keyValueBytes = String.format(keyValue,e.getKey(),e.getValue()).getBytes(); out.write(parameterLine); out.write(keyValueBytes); } } StringBuilder sb = new StringBuilder(); sb.append(boundaryPrefix); sb.append(boundary); sb.append(newLine); // 文件参数 sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + fileName + "\"" + newLine); sb.append("Content-Type:application/octet-stream"); // 参数头设置完以后需要两个换行,然后才是参数内容 sb.append(newLine); sb.append(newLine); // 将参数头的数据写入到输出流中 out.write(sb.toString().getBytes());// InputStream inputStream = FormatTools.getInstance().Byte2InputStream(bytesData);// // 数据输入流,用于读取文件数据// DataInputStream in = new DataInputStream(inputStream);// byte[] bufferOut = new byte[1024];// int bytes = 0;// // 每次读1KB数据,并且将文件数据写入到输出流中// while ((bytes = in.read(bufferOut)) != -1) {// out.write(bufferOut, 0, bytes);// } out.write(bytesData); // 最后添加换行 out.write(newLine.getBytes());// in.close(); // 定义最后数据分隔线,即--加上boundary再加上--。 byte[] end_data = (newLine + boundaryPrefix + boundary + boundaryPrefix + newLine).getBytes(); // 写上结尾标识 out.write(end_data); out.flush(); out.close(); // 定义BufferedReader输入流来读取URL的响应 StringBuffer sbOutPut=new StringBuffer(); BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { sbOutPut.append(line); } return sbOutPut.toString(); } catch (Exception e) { System.out.println("发送POST请求出现异常!" + e); e.printStackTrace(); return null; } }
接下来的问题是:Android UI主线程直接发起网络请求时会报错:
有段英文描述说的很明白:The exception that is thrown when an application attempts to perform a networking operation on its main thread.
意思是:当应用程序在主线程里尝试执行一个网络操作时会得到这个错误:解决办法很多,例如Handler post Message或AysncTask等;例如下面的代码:
private class UploadImageTask extends AsyncTask { @Override protected Object doInBackground(Object[] objects) { String requestHost = mcontext.getString(R.string.host_url); ShareFileHelper fh = new ShareFileHelper(); Bitmap bmp = ScreenShot.takeScreenShot(view); return fh.uploadImage(requestHost,"abc_456.jpg", bmp); } @Override protected void onPostExecute(Object obj) { String urlResult = obj.toString(); txtUrl.setText(urlResult); Bitmap bitmap = QRCodeUtil.createQRCodeBitmap(urlResult,300,300); imageView.setImageBitmap(bitmap); super.onPostExecute(obj); } }
上面是一段上传图片,并生产二维码的过程。写到这里有一个思考:如果程序中有大量的网络请求需要也要这样定义大量AsyncTask子类吗?是否有HttpUrlConnection的异步执行方式,例如 asyncExecute(). 这样可以简化UI线程的代码量。调用也十分方便。可是SDK库没有这样的接口,百度得来可以对HttpURLConnection进行异步封装,也是把Thread的调用封装到请求中,实际执行没有测试过:
贴代码参考:
参考源:对android HttpUrlConnection的轻量级封装(仿xutils3)
https://blog.csdn.net/qq_35596407/article/details/52528412
private static Handler handler = new Handler(); public static void get(final Map strMap, final String strUrl, final HttpCallBack callBack) { Thread thread = new Thread() { @Override public void run() { HttpURLConnection connection = null; InputStream is = null; try { StringBuilder stringBuffer = new StringBuilder(strUrl); stringBuffer.append("?"); for (Object key : strMap.keySet()) { stringBuffer.append(key + "=" + strMap.get(key) + "&"); } stringBuffer.deleteCharAt(stringBuffer.length() - 1); URL url = new URL(stringBuffer.toString()); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(10 * 1000); if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { is = connection.getInputStream(); final String result = InputStreamToString(is); handler.post(new Runnable() { @Override public void run() { callBack.onSuccess(result); } }); } else { throw new Exception("ResponseCode:" + connection.getResponseCode()); } } catch (final Exception e) { e.printStackTrace(); handler.post(new Runnable() { @Override public void run() { callBack.onError(e); } }); } finally { if (connection != null) connection.disconnect(); if (is != null) try { is.close(); } catch (IOException e) { e.printStackTrace(); } handler.post(new Runnable() { @Override public void run() { callBack.onFinish(); } }); } } }; thread.start(); } public static void post(final Map strMap, final String strUrl, final HttpCallBack callBack) { Thread thread = new Thread() { @Override public void run() { HttpURLConnection connection = null; OutputStream os = null; InputStream is = null; try { StringBuilder stringBuilder = new StringBuilder(); for (Object key : strMap.keySet()) { stringBuilder.append(key + "=" + strMap.get(key) + "&"); } stringBuilder.deleteCharAt(stringBuilder.length() - 1); URL url = new URL(strUrl); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setConnectTimeout(10 * 1000); connection.setDoOutput(true); connection.setDoInput(true); connection.setUseCaches(false); connection.setRequestProperty("Charset", "utf-8"); connection.connect(); os = connection.getOutputStream(); os.write(stringBuilder.toString().getBytes()); os.flush(); if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { is = connection.getInputStream(); final String result = InputStreamToString(is); handler.post(new Runnable() { @Override public void run() { callBack.onSuccess(result); } }); } else { throw new Exception("ResponseCode:" + connection.getResponseCode()); } } catch (final Exception e) { handler.post(new Runnable() { @Override public void run() { callBack.onError(e); } }); } finally { if (connection != null) connection.disconnect(); try { if (is != null) is.close(); if (os != null) os.close(); } catch (IOException e) { e.printStackTrace(); } handler.post(new Runnable() { @Override public void run() { callBack.onFinish(); } }); } } }; thread.start(); } public static String InputStreamToString(InputStream is) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = -1; while ((len = is.read(data)) != -1) { os.write(data, 0, len); } os.flush(); os.close(); String result = new String(data, "UTF-8"); return result; } public interface HttpCallBack { public void onSuccess(String result); public void onError(Exception e); public void onFinish(); }
附加一个利用URLConnection的Post和Get请求:
public static String sendPost(String url, String param) { String charset = "utf-8"; PrintWriter out = null; BufferedReader in = null; String result = ""; String line; StringBuffer sb=new StringBuffer(); try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 设置请求格式 conn.setRequestProperty("contentType", charset); conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //设置超时时间 conn.setConnectTimeout(30000); conn.setReadTimeout(30000); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 设置接收格式 in = new BufferedReader( new InputStreamReader(conn.getInputStream(),charset)); while ((line = in.readLine()) != null) { sb.append(line); } result=sb.toString(); } catch (Exception e) { System.out.println("发送 POST请求出现异常!"+e); e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally{ try{ if(out!=null){ out.close(); } if(in!=null){ in.close(); } } catch(IOException ex){ ex.printStackTrace(); } } return result; }public static String sendGet(String url, String param) { String result = ""; String charset = "utf-8"; String line; StringBuffer sb=new StringBuffer(); BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 设置请求格式 conn.setRequestProperty("contentType", charset); conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //设置超时时间 conn.setConnectTimeout(30000); conn.setReadTimeout(30000); // 建立实际的连接 conn.connect(); // 定义 BufferedReader输入流来读取URL的响应,设置接收格式 in = new BufferedReader(new InputStreamReader( conn.getInputStream(),charset)); while ((line = in.readLine()) != null) { sb.append(line); } result=sb.toString(); } catch (Exception e) { System.out.println("发送GET请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; }
更多相关文章
- mybatisplus的坑 insert标签insert into select无参数问题的解决
- Python技巧匿名函数、回调函数和高阶函数
- python list.sort()根据多个关键字排序的方法实现
- android EditText设置不可写
- android“设置”里的版本号
- 在Fragment中设置控件点击方法,执行失败。
- android中文api(89)——ViewManager
- Android(安卓)闹钟管理类的使用
- Android设置通知栏/状态栏透明改变通知栏颜色和app最上部分颜色