HttpUrlConnection和文件问题

时间:2014-10-14 04:31:51

标签: java httpurlconnection multipart

很抱歉再次提起这件事。当我第一次开始开发我的Android应用程序时,我正在使用HttpClient。我意识到谷歌正式将这个类弃用于最新版本的Android;他们鼓励开发人员使用HttpUrlConnection。

当我尝试将文件(JPEG)上传到我在GAE上托管的PHP Server API时,我最近遇到了问题。我花了很多精力来使用Multipart来实现这一目标。我最终使用了以下课程。但它仍然不能用于一些未知的原因。我的PHP Server API成功接收了我的POST数据但无法接收我的文件。我的代码出了什么问题?

如果您想知道,我可以使用isset($_FILES["profile_picture"])验证我是否收到了与我的服务器无关的信息。

这是我的班级:

package net.XXXXX;

import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.HttpsURLConnection;


public class MultipartUtility {

    private HttpURLConnection mConnection;
    private OutputStream outputStream;
    private PrintWriter mWriter;
    private final String boundary;

    private static final String LINE_FEED = "\r\n";
    private final static String CHARSET = "UTF-8";
    private final static String API_URL = "https://select-connection.appspot.com/";
    public static final String LOG_TAG = "APIRequestHandler";
    public static final int CONNECT_TIMEOUT = 15000;
    public static final int READ_TIMEOUT = 10000;

    /**
     * ...
     */
    public MultipartUtility() throws IOException {

        // creates a unique boundary based on time stamp.
        boundary = "===" + System.currentTimeMillis() + "===";

        URL url = new URL(API_URL);
        mConnection = (HttpsURLConnection)url.openConnection();
        mConnection.setConnectTimeout(CONNECT_TIMEOUT);
        mConnection.setReadTimeout(READ_TIMEOUT);
        mConnection.setRequestMethod("POST");
        mConnection.setRequestProperty("Accept-Charset", "UTF-8");
        mConnection.setRequestProperty("Accept", "application/json");
        mConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        mConnection.setUseCaches (false);
        mConnection.setDoInput(true);
        mConnection.setDoOutput(true);

        outputStream = mConnection.getOutputStream();
        mWriter = new PrintWriter(new OutputStreamWriter(outputStream, CHARSET), true);
    }

    /**
     * ...
     */
    public void addFormField(String name, String value) {
        mWriter.append("--" + boundary).append(LINE_FEED)
                .append("Content-Disposition: form-data; name=\"" + name + "\"")
                .append(LINE_FEED)
                .append("Content-Type: text/plain; charset=" + CHARSET)
                .append(LINE_FEED)
                .append(LINE_FEED)
                .append(value)
                .append(LINE_FEED);
        mWriter.flush();
    }

    /**
     * ...
     */
    public void addFilePart(String fieldName, File uploadFile)
            throws IOException {
        String fileName = uploadFile.getName();
        mWriter.append("--" + boundary).append(LINE_FEED)
                .append("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"")
                .append(LINE_FEED)
                .append("Content-Type: " + URLConnection.guessContentTypeFromName(fileName))
                .append(LINE_FEED)
                .append("Content-Transfer-Encoding: binary")
                .append(LINE_FEED)
                .append(LINE_FEED);
        mWriter.flush();

        FileInputStream inputStream = new FileInputStream(uploadFile);
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.flush();
        inputStream.close();

        mWriter.append(LINE_FEED);
        mWriter.flush();
    }

    /**
     * ...
     */
    public void addHeaderField(String name, String value) {
        mWriter.append(name + ": " + value).append(LINE_FEED);
        mWriter.flush();
    }

    /**
     * ...
     */
    public String finish() throws IOException {
        String response;

        mWriter.append(LINE_FEED).flush();
        mWriter.append("--" + boundary + "--").append(LINE_FEED);
        mWriter.close();

        // checks server's status code first
        int status = mConnection.getResponseCode();
        if (status == HttpURLConnection.HTTP_OK) {

            response = ApiRequestHandler.convertStreamToString(new BufferedInputStream(mConnection.getInputStream()));

            mConnection.disconnect();
        } else {
            throw new IOException("Server returned non-OK status: " + status);
        }

        return response;
    }
}

这就是我使用它的方式:

try {
                MultipartUtility connection = new MultipartUtility();
                connection.addFormField("action", "update_picture");
                connection.addFormField("user_id", mUserId);
                connection.addFormField("session_token", mSessionToken);
                connection.addFilePart("profile_picture", mProfilePicture);
                String result = connection.finish();
                Log.d("PROFILE PICTURE", result);
            } catch (IOException e) {
                e.printStackTrace();
            }

2 个答案:

答案 0 :(得分:1)

需要多部分吗?如果您只需要使用POST请求发送一个文件,则只需将其二进制数据写入连接的输出流即可。 (我没有使用PHP的经验,但我认为PHP将能够读取请求体)。其他字段可以作为查询参数或HTTP标头进行传输。

我还建议通过Fiddler2等日志代理路由HTTP流量,以查看HTTP请求正文中的实际内容(并将其与工作测试示例进行比较)。

答案 1 :(得分:0)

我终于找到了问题。谢谢mjn为我提供了Fiddler2 Web调试解决方案。使用这个软件,我能够编写一个有效的HTTP请求来测试我的服务器API。这个问题与我的代码无关。 PHP无法接收上传文件的原因是因为Google App Engine会自动拒绝每个上传的文件。要上传文件,您需要先创建一个上传网址。

来源:https://cloud.google.com/appengine/docs/php/googlestorage/user_upload