【问题标题】:Android: upload file with filling out POST body togetherAndroid:上传文件与填写POST正文一起
【发布时间】:2025-12-22 14:00:12
【问题描述】:

我确实使用 MultipartEntity 将文件发送到服务器,它在$_FILES superglobal 中正确显示

但我还需要填写 POST 正文以通过 php://stdin 读取

我该怎么做?

下面的当前sn-p:

ByteArrayOutputStream bos = new ByteArrayOutputStream(); // stream to hold image
bm.compress(CompressFormat.JPEG, 75, bos); //compress image
byte[] data = bos.toByteArray(); 
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("REMOTE ADDRESS");
ByteArrayBody bab = new ByteArrayBody(data, "image.jpg");
MultipartEntity reqEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE); // is this one causing trouble?
reqEntity.addPart("image", bab); // added image to request
// tried this with no luck
// reqEntity.addPart("", new StringBody("RAW DATA HERE")); 
postRequest.setEntity(reqEntity); // set the multipart entity to http post request
HttpResponse response = httpClient.execute(postRequest);

MultipartEntity 是 HttpMime 4.1.2 API 的一部分,documentation

与此类似:Android: Uploading a file to a page along with other POST strings

【问题讨论】:

    标签: java php android file-upload multipartentity


    【解决方案1】:

    只需在您的MultipartEntity 中添加几个FormBodyPart

    您可以使用StringBody 对象来提供值。

    这是一个如何使用它的示例:

    byte[] data = {10,10,10,10,10}; 
    HttpClient httpClient = new DefaultHttpClient();
    HttpPost postRequest = new HttpPost("server url");
    ByteArrayBody bab = new ByteArrayBody(data, "image.jpg");
    MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
    reqEntity.addPart("image", bab);
    
    FormBodyPart bodyPart=new FormBodyPart("formVariableName", new StringBody("formValiableValue"));
    reqEntity.addPart(bodyPart);
    bodyPart=new FormBodyPart("formVariableName2", new StringBody("formValiableValue2"));
    reqEntity.addPart(bodyPart);
    bodyPart=new FormBodyPart("formVariableName3", new StringBody("formValiableValue3"));
    reqEntity.addPart(bodyPart); 
    postRequest.setEntity(reqEntity);
    HttpResponse response = httpClient.execute(postRequest);
    BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
    String line = null;
    while((line = in.readLine()) != null) {
        System.out.println(line);
    }
    

    这是 PHP 脚本的输出:

    $_FILES
    Array
    (
        [image] => Array
            (
                [name] => image.jpg
                [type] => application/octet-stream
                [tmp_name] => /tmp/php6UHywL
                [error] => 0
                [size] => 5
            )
    
    )
    $_POST:
    Array
    (
        [formVariableName] => formValiableValue
        [formVariableName2] => formValiableValue2
        [formVariableName3] => formValiableValue3
    )
    

    这不会压缩一个内容正文部分内的所有帖子变量,但它完成了这项工作。

    您无法访问来自php://stdin$HTTP_RAW_POST_DATA 的数据,两者都不能用于多部分/表单数据编码。来自 PHP 文档:

    php://input 是一个只读流,允许您读取原始数据 从请求正文。在 POST 请求的情况下,最好 使用 php://input 而不是 $HTTP_RAW_POST_DATA 因为它没有 依赖于特殊的 php.ini 指令。此外,对于那些情况 $HTTP_RAW_POST_DATA 默认不填充,它是一个潜在的 激活时内存占用较少的替代方案 always_populate_raw_post_data。 php://input 不适用于 enctype="multipart/form-data"。

    即使您将always_populate_raw_post_data 设置为 On,它仍然无法解决问题:

    始终填充包含原始 POST 数据的 $HTTP_RAW_POST_DATA。 否则,仅使用无法识别的 MIME 类型填充变量 的数据。但是,访问原始 POST 的首选方法 数据是 php://input。 $HTTP_RAW_POST_DATA 不适用于 enctype="multipart/form-data"。

    我最好的猜测是将所有数据添加为ByteArrayBodyStringBody,然后 使用它,就好像你正在阅读 php://stdin

    这里是ByteArrayBody的例子:

    String testString="b=a&c=a&d=a&Send=Send";
    reqEntity.addPart(new FormBodyPart("formVariables", new ByteArrayBody(testString.getBytes(), "application/x-www-form-urlencoded", "formVariables")));
    

    在 PHP 中:

    var_dump(file_get_contents($_FILES['formVariables']['tmp_name']));
    

    你应该得到:

    字符串(21) "b=a&c=a&d=a&Send=Send"

    编辑:经过再三考虑,我认为最好只使用一个StringBody 并将所有数据放在一个 post 变量中,然后从中解析它,它会跳过将数据写入文件并在请求后将其删除由于临时文件完全没用,这将提高性能。 这是一个例子:

    String testString="b=a&c=a&d=a&Send=Send";
    bodyPart=new FormBodyPart("rawData", new StringBody(testString));
    reqEntity.addPart(bodyPart);
    

    然后来自 PHP:

    var_dump($_POST['rawData']);
    

    【讨论】:

    • 能否请您扩展您的问题并添加示例代码等?谢谢
    • 我扩展并更正了答案,这适用于普通 java,没有理由不应该在 android 上运行。
    • 嘿,谢谢。现在,您能否考虑一下,然后编辑您的答案以匹配问题?我不需要发送表单数据(类似于在 HTML 中发布表单),但我需要发布原始数据,类似于 $.ajax("raw data"),以这种方式发送的数据在 $_POST 超全局中无法读取,我需要发送与 HttpDefaultClient 一起使用的 StringEntity 之类的东西
    • 哦,抱歉没有从 php://stdin 行中得到它 :),让我考虑一下,我会回复你
    • 我做了更多的研究,你不能使用 php://stdin 或 php://input(在这种情况下是相同的)甚至 $HTTP_POST_VARS,它们对于 multipart/ 被禁用表单数据请求。我编辑了我的帖子以反映建议的解决方法。