【问题标题】:Android HTTP POST file upload not working with HttpUrlConnectionAndroid HTTP POST文件上传不适用于HttpUrlConnection
【发布时间】:2013-07-25 11:41:41
【问题描述】:

我正在尝试从我的设备通过 HTTP POST 将文件上传到服务器。我有两种方法upload1和upload2。

Upload1 使用 HttpPost 类并且它可以工作,但是对于更大的文件它会抛出内存不足异常。

Upload2 使用 HttpURLConnection 并且它不起作用。 (我从服务器收到 BAD REQUEST 消息。)我希望 upload2 工作,因为它使用流来发送数据并且不会引发内存不足异常。 我在wireshark中查看了包,headers似乎是一样的,但是upload1的长度是380,upload2只有94。可能是什么问题?

private void upload1(File file) {

        try {
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(url + "?recname="
                    + fileName);

            // ///////////////////////////////////////
            String lineEnd = "\r\n";
            String twoHyphens = "--";
            String boundary = "---------------------------This is the boundary";

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);

            FileInputStream fin = new FileInputStream(file);

            byte audioData[] = new byte[(int) file.length()];

            fin.read(audioData);
            fin.close();

            // Send a binary file
            dos.writeBytes(twoHyphens + boundary + lineEnd);

            dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\""
                    + fileName + "\"" + lineEnd);
            dos.writeBytes("Content-Type: audio/mp4" + lineEnd);
            dos.writeBytes("Content-Transfer-Encoding: binary" + lineEnd);
            dos.writeBytes(lineEnd);
            dos.write(audioData);
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
            dos.flush();
            dos.close();

            ByteArrayInputStream content = new ByteArrayInputStream(
                    baos.toByteArray());
            BasicHttpEntity entity = new BasicHttpEntity();
            entity.setContent(content);

            entity.setContentLength(baos.toByteArray().length);

            httppost.addHeader("Content-Type", "multipart/form-data; boundary="
                    + boundary);

            httppost.setEntity(entity);

            // //////////////////////////////////

            HttpResponse response = httpclient.execute(httppost);

            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    response.getEntity().getContent(), "UTF-8"));
            StringBuilder builder = new StringBuilder();

            for (String line = null; (line = reader.readLine()) != null;) {
                builder.append(line).append("\n");
            }

            reader.close();
            message = builder.toString();
            System.out.println(message);

        } catch (UnknownHostException e) {
            message = "Error! Server is unreachable. Check you internet connection!";
        } catch (Exception e) {
            message = "error: " + e.toString();
        }

    }

/////////////////////////////////////// /////////////////////////////////////////////p>

private void upload2(File file) {

        HttpURLConnection connection = null;

        String pathToOurFile = file.getPath();
        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "---------------------------This is the boundary";

        int bytesRead, bytesAvailable, bufferSize;
        byte[] buffer;
        int maxBufferSize = 1 * 1024 * 1024;

        try {

            fileInputStream = new FileInputStream(new File(pathToOurFile));

            URL server_url = new URL(url+ "?recname="
                    + fileName);
            connection = (HttpURLConnection) server_url.openConnection();

            // Allow Inputs & Outputs
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);

            // Enable POST method
            connection.setRequestMethod("POST");

            String bodyHeader = twoHyphens
                    + boundary
                    + lineEnd
                    + "Content-Disposition: form-data; name=\"file\";filename=\""
                    + fileName + "\"" + lineEnd + "Content-Type: audio/mp4"
                    + lineEnd + "Content-Transfer-Encoding: binary" + lineEnd
                    + lineEnd + twoHyphens + boundary + twoHyphens ;

            byte[] bodyHeaderAray = bodyHeader.getBytes();

            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type",
                    "multipart/form-data;boundary=" + boundary);
            connection.setRequestProperty("Expect", "100-continue");

            // Content-Length
            int bodyHeaderSize = (int) file.length() + bodyHeaderAray.length;
            System.out.println("body header size: " + bodyHeaderSize);
            // connection.setFixedLengthStreamingMode(bodyHeaderSize);

            outputStream = new DataOutputStream(connection.getOutputStream());
            outputStream.writeBytes(twoHyphens + boundary + lineEnd);
            outputStream
                    .writeBytes("Content-Disposition: form-data; name=\"file\";filename=\""
                            + fileName + "\"");
            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes("Content-Type: audio/mp4" + lineEnd);
            outputStream.writeBytes("Content-Transfer-Encoding: binary"
                    + lineEnd);

            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];

            // Read file
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);

            while (bytesRead > 0) {
                outputStream.write(buffer, 0, bufferSize);
                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            }

            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes(twoHyphens + boundary + twoHyphens
                    + lineEnd);

            fileInputStream.close();
            outputStream.flush();
            outputStream.close();

            // Responses from the server (code and message)
            int serverResponseCode = connection.getResponseCode();
            String serverResponseMessage = connection.getResponseMessage();

            message = serverResponseMessage;

        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

【问题讨论】:

    标签: android http-post out-of-memory httpurlconnection


    【解决方案1】:

    根据您上传文件时遇到的问题。您应该使用 Multipart 机制将文件上传到服务器。

        httpclient-4.1.jar
        httpcore-4.1.jar
        httpmime-4.1.jar
        apache-mime4j-0.6.1.jar
    

    为此,您需要在项目中添加几个库并将其用于 HTTP 连接和文件数据。

        private boolean uploadFile(File mFile) {
                boolean success = true;
                String filename = mFile.getName();
                MultipartEntity data_to_send = new MultipartEntity(
                        HttpMultipartMode.BROWSER_COMPATIBLE);
                try {
                    data_to_send.addPart(
                            "name",
                            new StringBody(
                                    filename.substring(filename.lastIndexOf("/") + 1)));
                    data_to_send.addPart("fileData", new FileBody(mFile));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                try {
                    String responseData = ConsumeWebService.sendRequest(data_to_send,
                            Global.BASE_URL + serviceUrl);
                    if (TextUtils.isEmpty(responseData)
                            || responseData.equals(ConsumeWebService.ERROR_CODE)) {
                        success = false;
                    }
                } catch (Exception e) {
                    success = false;
                    e.printStackTrace();
                }
                return success;
            }
    
    
    public static String sendRequest(MultipartEntity data, String url) {
            String response = "";
            response = postData(url, data);
            return response;
        }
    
    
    private static String postData(String url, MultipartEntity data) {
            String strResponse = "";
    
            try {
                Log.d(Global.TAG, "Post URL is " + url);
                HttpPost httpPost = new HttpPost(url);
                httpPost.setEntity(data);
                strResponse = httpClient.execute(httpPost,
                        new BasicResponseHandler());
            } catch (UnsupportedEncodingException e) {
                strResponse = ERROR_CODE;
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                strResponse = ERROR_CODE;
                e.printStackTrace();
            } catch (IOException e) {
                strResponse = ERROR_CODE;
                e.printStackTrace();
            }
            return strResponse;
        }
    

    【讨论】:

    • 我不知道这些库。 MultipartEntity 是否负责流式传输文件?我担心这个库会再次出现内存不足异常。
    • 这个库你可以通过谷歌搜索下载。这个库足够强大,可以处理内存不足。所以不要担心那部分
    • MultipartEntity 当前已弃用。 Apache 建议改用 MultipartEntityBuilder (hc.apache.org/httpcomponents-client-4.3.x/httpmime/examples/org/…),但我还没有设法让它适用于 Android。
    【解决方案2】:

    您可以通过关注this w3.org docs about forms 自行构建您的 POST 请求。

    我认为在 upload2 中你缺少了一个 lineEnd 你做的地方:

    ....
    outputStream.writeBytes("Content-Transfer-Encoding: binary"
                    + lineEnd);
    

    在此之后,您必须传输数据,并且在实际数据之前需要两个lineEnds,因此应该是:

    ....
    outputStream.writeBytes("Content-Transfer-Encoding: binary"
                    + lineEnd + lineEnd);
    


    对于读取文件并将它们放置在 multipart/form-data 结构中,我建议您采用适合我的方式:

    FileInputStream fileInputStream=new FileInputStream(file);
    byte[] bytes= new bytes[fileInputStream.getChannel().size()];
    fileInputStream.read(bytes);
    fileInputStream.close();
    outputStream.write(bytes);
    outputStream.writeBytes(lineEnd);
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-22
      相关资源
      最近更新 更多