You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一连接中URL编码数据并上传文件失败:问题排查与实现方案

问题分析与解决方案

你遇到的问题核心在于没有遵循multipart/form-data请求的格式规范——你直接把URL编码的表单数据写入了输出流,但multipart请求要求每个参数(无论是普通文本还是文件)都必须作为一个独立的"part",用你定义的boundary分隔开,并且带有正确的头信息。直接写入URL编码的数据会破坏整个请求的结构,导致服务器无法正确解析。

要在同一个POST请求中同时发送普通数据和文件,所有内容都需要封装在multipart的各个part里。普通文本数据也要作为一个单独的part,和文件part一样用boundary分隔,并且指定name属性。

修正后的Android代码

HttpURLConnection conn = null;
DataOutputStream dos = null;
String existingFileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recorded_audio.3gp";
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1 * 1024 * 1024;
String urlString = "http://mywebsite.com/uploadAudio.php";

@Override
protected String doInBackground(String... params) {
    String uploading_file = params[0];
    try {
        FileInputStream fileInputStream = new FileInputStream(new File(uploading_file));
        URL url = new URL(urlString);
        conn = (HttpURLConnection) url.openConnection();
        
        // 基础配置保持不变
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
        
        dos = new DataOutputStream(conn.getOutputStream());
        
        // 1. 发送普通文本数据作为一个multipart part
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\"user\"" + lineEnd);
        dos.writeBytes(lineEnd); // 空行分隔头和内容
        
        // 构造并写入JSON数据(不需要URLEncoder,multipart会处理编码)
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", "my_data");
        JSONObject data = new JSONObject();
        data.put("user_data", jsonObject);
        String jsonStr = data.toString();
        dos.writeBytes(jsonStr + lineEnd);
        
        // 2. 发送文件作为另一个multipart part
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + uploading_file + "\"" + lineEnd);
        dos.writeBytes(lineEnd);
        
        // 写入文件内容
        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];
        bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        while (bytesRead > 0) {
            dos.write(buffer, 0, bufferSize);
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        }
        
        // 结束multipart请求
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
        
        // 关闭流
        fileInputStream.close();
        dos.flush();
        dos.close();
        
    } catch (MalformedURLException ex) {
        Log.e("Debug", "error: " + ex.getMessage(), ex);
    } catch (IOException ioe) {
        Log.e("Debug", "error: " + ioe.getMessage(), ioe);
    } catch (JSONException e) {
        e.printStackTrace();
    }
    
    // 处理服务器响应
    String line = "";
    try {
        InputStream inputStream = conn.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
        if ((line = bufferedReader.readLine()) != null) {
            Log.e("Debug", "Server Response " + line);
        }
        bufferedReader.close();
        inputStream.close();
        conn.disconnect();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return line;
}

对应的PHP服务器端代码

<?php
// 接收普通文本数据(JSON格式)
$userData = json_decode($_POST['user'], true);
if ($userData) {
    $userId = $userData['user_data']['id'];
    echo "Received user ID: " . $userId . "\n";
}

// 接收上传的文件
$targetDir = "uploads/";
// 确保uploads目录存在
if (!file_exists($targetDir)) {
    mkdir($targetDir, 0777, true);
}
$targetFile = $targetDir . basename($_FILES["uploadedfile"]["name"]);

if (move_uploaded_file($_FILES["uploadedfile"]["tmp_name"], $targetFile)) {
    echo "The file ". basename( $_FILES["uploadedfile"]["name"]). " has been uploaded.";
} else {
    echo "Sorry, there was an error uploading your file.";
}
?>

关键注意点

  • 不要混合URL编码和multipart格式:multipart请求会自动处理参数的编码,不需要手动用URLEncoder处理普通数据。
  • 每个part必须用boundary分隔:每个参数(文本或文件)都要以--boundary开头,然后是头信息、空行、内容,最后用--boundary--标记结束整个请求。
  • 确保流操作顺序正确:写完所有part后一定要发送结束标记,否则服务器会认为请求不完整。
  • 权限配置:Android端需要添加INTERNET权限,针对Android 10及以下还需WRITE_EXTERNAL_STORAGE权限;PHP端要确保uploads目录有可写权限。

内容的提问来源于stack exchange,提问作者Saurabh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:45:02