Android中使用HttpPost发送带参数和文件的请求

28
我需要上传一些数据到PHP服务器。我可以使用参数进行发布:
String url = "http://yourserver";

HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
nameValuePairs.add(new BasicNameValuePair("user", "username"));
nameValuePairs.add(new BasicNameValuePair("password", "password"));
try {
    httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
    httpClient.execute(httpPost);
}

我也能上传文件:

String url = "http://yourserver";
File file = new File(Environment.getExternalStorageDirectory(),
        "yourfile");
try {
    HttpClient httpclient = new DefaultHttpClient();

    HttpPost httppost = new HttpPost(url);

    InputStreamEntity reqEntity = new InputStreamEntity(
            new FileInputStream(file), -1);
    reqEntity.setContentType("binary/octet-stream");
    reqEntity.setChunked(true); // Send in multiple parts if needed
    httppost.setEntity(reqEntity);
    HttpResponse response = httpclient.execute(httppost);
    //Do something with response...
}

但是我该如何组合它呢?我需要在一个POST请求中上传图像和参数。 谢谢


添加最新的jar文件只会增加0.2MB的大小。 - Vihaan Verma
我一直在寻找一个简单的上传图片代码,你救了我一命。我根本不明白只需要在上面放置一个InputStreamEntity就可以了。我知道还有其他更复杂的方法,但那不是我所需要的。 - Warpzit
5个回答

13

你需要使用 MultipartEntity。在线找到并下载这两个库:httpmime-4.0.jarapache-mime4j-0.4.jar,然后你就可以附加任意数量的文件了。以下是如何使用它的示例:

HttpPost httpost = new HttpPost("URL_WHERE_TO_UPLOAD");
MultipartEntity entity = new MultipartEntity();
entity.addPart("myString", new StringBody("STRING_VALUE"));
entity.addPart("myImageFile", new FileBody(imageFile));
entity.addPart("myAudioFile", new FileBody(audioFile));
httpost.setEntity(entity);
HttpResponse response;
response = httpclient.execute(httpost);

对于服务器端,您可以使用这些实体标识符名称myImageFilemyStringmyAudioFile


你是不是指的是apache-mime4j-0.6.jar和httpmime-4.0.1.jar?因为我收到了“找不到org.....filed.Fields.content”错误。 - wwjdm
是的,apache-mime4j-0.6.jar和httpmime-4.0.1.jar是更新的版本。 - Marcin S.
在我的客户端应用程序中,在执行此行代码 MultipartEntity entity = new MultipartEntity(); 时崩溃了。我已经包含了必要的JAR文件。有什么想法吗? - macOsX
无法在服务器端接收数据。所有字段在服务器上都显示为空! - Rohitesh

11

您必须使用多部分HTTP POST,就像在HTML表单中一样。这可以通过使用额外的库来实现。 请参考发送图像使用Http Post来获取完整示例。


4

这对我来说非常有效:

public int uploadFile(String sourceFileUri) {  

    String fileName=sourceFileUri;
    HttpURLConnection conn = null;
    DataOutputStream dos = null;  
    String lineEnd = "\r\n";
    String twoHyphens = "--";
    String boundary = "------hellojosh";
    int bytesRead, bytesAvailable, bufferSize;
    byte[] buffer;
    int maxBufferSize = 1 * 1024 * 1024; 
    File sourceFile = new File(fileName); 
    Log.e("joshtag", "Uploading: sourcefileURI, "+fileName);

    if (!sourceFile.isFile()) {                                
         Log.e("uploadFile", "Source File not exist :"+appSingleton.getInstance().photouri);//FullPath);                
         runOnUiThread(new Runnable() {
            public void run() {             
                //messageText.setText("Source File not exist :"
                }
            });          
         return 0;  //RETURN #1
         }
    else{
        try{                

             FileInputStream fileInputStream = new FileInputStream(sourceFile);           
             URL url = new URL(upLoadServerUri);
             Log.v("joshtag",url.toString());

             // Open a HTTP  connection to  the URL
             conn = (HttpURLConnection) url.openConnection(); 
             conn.setDoInput(true); // Allow Inputs
             conn.setDoOutput(true); // Allow Outputs
             conn.setUseCaches(false); // Don't use a Cached Copy            s       
             conn.setRequestMethod("POST");                     
             conn.setRequestProperty("Connection", "Keep-Alive");
             conn.setRequestProperty("ENCTYPE", "multipart/form-data");
             conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);     
             conn.setRequestProperty("file", fileName);                     
             conn.setRequestProperty("user", user_id));

             dos = new DataOutputStream(conn.getOutputStream());  
             //ADD Some -F Form parameters, helping method
             //... is declared down below
             addFormField(dos, "someParameter", "someValue");

             dos.writeBytes(twoHyphens + boundary + lineEnd); 
             dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + fileName + "\"" + lineEnd);                    
             dos.writeBytes(lineEnd);      

             // create a buffer of  maximum size
             bytesAvailable = fileInputStream.available();           
             bufferSize = Math.min(bytesAvailable, maxBufferSize);
             buffer = new byte[bufferSize];         
             // read file and write it into form...
             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);
                    Log.i("joshtag","->");
                    }

             // send multipart form data necesssary after file data...
             dos.writeBytes(lineEnd);
             dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

             // Responses from the server (code and message)
             serverResponseCode = conn.getResponseCode();
             String serverResponseMessage = conn.getResponseMessage().toString();              
             Log.i("joshtag", "HTTP Response is : "  + serverResponseMessage + ": " + serverResponseCode);  

             // ------------------ read the SERVER RESPONSE
             DataInputStream inStream;
             try {
                 inStream = new DataInputStream(conn.getInputStream());
                 String str;
                 while ((str = inStream.readLine()) != null) {
                     Log.e("joshtag", "SOF Server Response" + str);
                    }
                 inStream.close();
                }
             catch (IOException ioex) {
                Log.e("joshtag", "SOF error: " + ioex.getMessage(), ioex);
                }

             //close the streams //
             fileInputStream.close();
             dos.flush();
             dos.close();    

             if(serverResponseCode == 200){ 
                //Do something                       
                }//END IF Response code 200  

            dialog.dismiss();
            }//END TRY - FILE READ      
        catch (MalformedURLException ex) {
            ex.printStackTrace();     
            Log.e("joshtag", "UL error: " + ex.getMessage(), ex);  
            } //CATCH - URL Exception

         catch (Exception e) {           
            e.printStackTrace();             
            Log.e("Upload file to server Exception", "Exception : "+ e.getMessage(), e);
            } //

        return serverResponseCode; //after try       
        }//END ELSE, if file exists.
    }


public static String lineEnd = "\r\n";
public static String twoHyphens = "--";
public static String boundary = "------------------------afb19f4aeefb356c";
public static void addFormField(DataOutputStream dos, String parameter, String value){
    try {
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\""+parameter+"\"" + lineEnd);
        dos.writeBytes(lineEnd);
        dos.writeBytes(value);
        dos.writeBytes(lineEnd);
    }
    catch(Exception e){

    }
}

更新:如果您需要在文件上传时一同发送参数,请使用:

conn.setRequestProperty("someParameter","someValue")
//or
addFormField(DataOutputStream dos, String parameter, String value)

...如上面的代码所示。如果您要连接的服务器不是完全了解的,那么其中一个应该可以工作。


1
仅上传文件,不包含额外数据! - Lazar Kukolj
有什么额外的数据吗?@user6042879 - Josh
@Josh 如果我还需要发送名称-值对和文件一起发送怎么办? - Saeed Jassani
为什么不呢?你试过将值对作为.setRequestProperty或addFormField两者传递吗?@SaeedJassani - Josh
addFormField 不是一个方法,根据 .setRequestProperty 的文档,它设置请求头字段...... 因此我无法从服务器端提取 $_POST 数组中的值。 - Saeed Jassani
显示剩余4条评论

1

注意

MultiPartEntityBasicNameValuePair已经废弃

这里是新的做法!你只需要下载httpcore.jar(最新版)httpmime.jar(最新版),可以从Apache网站下载。

try
{
    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(URL);

    MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
    entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

    entityBuilder.addTextBody(USER_ID, userId);
    entityBuilder.addTextBody(NAME, name);
    entityBuilder.addTextBody(TYPE, type);
    entityBuilder.addTextBody(COMMENT, comment);
    entityBuilder.addTextBody(LATITUDE, String.valueOf(User.Latitude));
    entityBuilder.addTextBody(LONGITUDE, String.valueOf(User.Longitude));

    if(file != null)
    {
        entityBuilder.addBinaryBody(IMAGE, file);
    }

    HttpEntity entity = entityBuilder.build();
    post.setEntity(entity);
    HttpResponse response = client.execute(post);
    HttpEntity httpEntity = response.getEntity();
    result = EntityUtils.toString(httpEntity);
    Log.v("result", result);
}
catch(Exception e)
{
    e.printStackTrace();
}

这对我不起作用,服务器告诉我“它没有收到所有所需的参数”,而我只需要2个,照片和ID。 - Diego Rivera

0
请使用这个异步任务 async Task。
    class httpUploader2 extends AsyncTask<Void, Void, Void> {
    private final static String boundary =  "*****M9J_cfALt*****";
    private final static String multiPartFormData = "multipart/form-data;boundary=" + boundary;
    @Override
    protected Void doInBackground(Void... params) {
        HttpURLConnection urlConnection = null;
        try {
            URL url = new URL("http://192.168.43.20/test.php");
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setConnectTimeout(5000);
            urlConnection.setRequestProperty("Connection", "Keep-Alive");
            urlConnection.setRequestProperty("Cache-Control", "no-cache");
            urlConnection.setRequestProperty("Content-Type", multiPartFormData);
            urlConnection.setUseCaches( false );
            urlConnection.setChunkedStreamingMode(0);

            DataOutputStream request = new DataOutputStream(urlConnection.getOutputStream());
            writeField(request,"hellow","world");
            writeFile(request,"file1","testfilename.txt","this is file content as string".getBytes(StandardCharsets.UTF_8));
            writeField(request,"testtt","valueeee");
            writeFile(request,"file2","testfilename2222.txt","this is file content as string".getBytes(StandardCharsets.UTF_8));
            request.flush();
            request.close();

            int code = urlConnection.getResponseCode();
            if (code ==  HTTP_OK) {
                //Log.d("@#$","Connected");
                BufferedReader rd = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                String line;
                while ((line = rd.readLine()) != null) {
                    Log.i("@#$", line);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }

        return null;
    }
    private void writeField(DataOutputStream request,String name,String value){
        String out = "\r\n--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + name +"\"";
        out += "\r\n\r\n" + value;
        try {
            request.write(out.getBytes(StandardCharsets.UTF_8));
        } catch (IOException ignored) {}
    }
    private void writeFile(DataOutputStream request,String name,String value,byte[] filedata){
        String out = "\r\n--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + name +"\"; filename=\"" + value + "\"";
        out += "\r\n\r\n";
        try {
            request.write(out.getBytes(StandardCharsets.UTF_8));
            request.write(filedata);
        } catch (IOException ignored) {}
    }
}

请使用此 PHP 文件进行测试(test.php)-
<?php
var_dump($_REQUEST);
echo "--------UPLOADED FILES--------\n";
var_dump($_FILES);
?>

我正在使用真实测试设备上的Android Pie,因此需要在清单文件中声明,否则无法连接-

<application
        android:usesCleartextTraffic="true"
.
.
/></application>

使用xampp来测试PHP服务器。但是您无法直接在手机(真实测试设备)上访问它。为此,首先将计算机连接到设备热点。然后在Apache的httpd.txt中添加“Require all granted”。
然后要获取该热点网络下xampp的IP地址,请编写ipconfig并查找ipv4地址。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接