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<String,String> 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<String, String> 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;
    }

猜你喜欢

转载自blog.csdn.net/elie_yang/article/details/81636025
今日推荐