2009-07-01 184 views
51

我想編寫Java應用程序,它將使用PHP將文件上傳到Apache服務器。 Java代碼使用Jakarta HttpClient庫版本4.0β2:如何使用Java使用Java HttpClient庫上傳文件

import java.io.File; 
import org.apache.http.HttpEntity; 
import org.apache.http.HttpResponse; 
import org.apache.http.HttpVersion; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.entity.FileEntity; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.params.CoreProtocolPNames; 
import org.apache.http.util.EntityUtils; 


public class PostFile { 
    public static void main(String[] args) throws Exception { 
    HttpClient httpclient = new DefaultHttpClient(); 
    httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 

    HttpPost httppost = new HttpPost("http://localhost:9002/upload.php"); 
    File file = new File("c:/TRASH/zaba_1.jpg"); 

    FileEntity reqEntity = new FileEntity(file, "binary/octet-stream"); 

    httppost.setEntity(reqEntity); 
    reqEntity.setContentType("binary/octet-stream"); 
    System.out.println("executing request " + httppost.getRequestLine()); 
    HttpResponse response = httpclient.execute(httppost); 
    HttpEntity resEntity = response.getEntity(); 

    System.out.println(response.getStatusLine()); 
    if (resEntity != null) { 
     System.out.println(EntityUtils.toString(resEntity)); 
    } 
    if (resEntity != null) { 
     resEntity.consumeContent(); 
    } 

    httpclient.getConnectionManager().shutdown(); 
    } 
} 

的PHP文件upload.php很簡單:

<?php 
if (is_uploaded_file($_FILES['userfile']['tmp_name'])) { 
    echo "File ". $_FILES['userfile']['name'] ." uploaded successfully.\n"; 
    move_uploaded_file ($_FILES['userfile'] ['tmp_name'], $_FILES['userfile'] ['name']); 
} else { 
    echo "Possible file upload attack: "; 
    echo "filename '". $_FILES['userfile']['tmp_name'] . "'."; 
    print_r($_FILES); 
} 
?> 

閱讀中,我得到以下結果響應:

executing request POST http://localhost:9002/upload.php HTTP/1.1 
 
HTTP/1.1 200 OK 
Possible file upload attack: filename ''. 
Array 
(
) 

因此,請求成功,我能夠與服務器進行通信,但PHP確實沒有注意到文件 - 方法is_uploaded_file返回false$_FILES變量是空的。我不知道爲什麼會發生這種情況。我已跟蹤HTTP響應和請求和他們看起來OK:
要求是:

 
POST /upload.php HTTP/1.1 
Content-Length: 13091 
Content-Type: binary/octet-stream 
Host: localhost:9002 
Connection: Keep-Alive 
User-Agent: Apache-HttpClient/4.0-beta2 (java 1.5) 
Expect: 100-Continue 

˙Ř˙ŕ..... the rest of the binary file... 

和響應:

 
HTTP/1.1 100 Continue 

HTTP/1.1 200 OK 
Date: Wed, 01 Jul 2009 06:51:57 GMT 
Server: Apache/2.2.8 (Win32) DAV/2 mod_ssl/2.2.8 OpenSSL/0.9.8g mod_autoindex_color PHP/5.2.5 mod_jk/1.2.26 
X-Powered-By: PHP/5.2.5 
Content-Length: 51 
Keep-Alive: timeout=5, max=100 
Connection: Keep-Alive 
Content-Type: text/html 

Possible file upload attack: filename ''.Array 
(
) 

我都在本地的Windows XP XAMPP和遠程Linux服務器測試此。我也嘗試使用以前版本的HttpClient - 版本3.1 - 並且結果更加不清楚,is_uploaded_file返回false,但是$_FILES數組填充了正確的數據。

+0

DefaultHttpClient()現在已被棄用。 – 2015-01-20 08:31:38

回答

66

好吧,我用Java代碼是錯誤的,來這裏的正確Java類:使用MultipartEntity

import java.io.File; 
import org.apache.http.HttpEntity; 
import org.apache.http.HttpResponse; 
import org.apache.http.HttpVersion; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.entity.mime.MultipartEntity; 
import org.apache.http.entity.mime.content.ContentBody; 
import org.apache.http.entity.mime.content.FileBody; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.params.CoreProtocolPNames; 
import org.apache.http.util.EntityUtils; 


public class PostFile { 
    public static void main(String[] args) throws Exception { 
    HttpClient httpclient = new DefaultHttpClient(); 
    httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 

    HttpPost httppost = new HttpPost("http://localhost:9001/upload.php"); 
    File file = new File("c:/TRASH/zaba_1.jpg"); 

    MultipartEntity mpEntity = new MultipartEntity(); 
    ContentBody cbFile = new FileBody(file, "image/jpeg"); 
    mpEntity.addPart("userfile", cbFile); 


    httppost.setEntity(mpEntity); 
    System.out.println("executing request " + httppost.getRequestLine()); 
    HttpResponse response = httpclient.execute(httppost); 
    HttpEntity resEntity = response.getEntity(); 

    System.out.println(response.getStatusLine()); 
    if (resEntity != null) { 
     System.out.println(EntityUtils.toString(resEntity)); 
    } 
    if (resEntity != null) { 
     resEntity.consumeContent(); 
    } 

    httpclient.getConnectionManager().shutdown(); 
    } 
} 

音符。

+1

HttpComponents(即hc.apache.org NOT HttpClient-3.1)支持哪些新版本?我收到錯誤消息:「類型org.apache.james.mime4j.message.SingleBody無法解析,它是從所需的.class文件間接引用」 – therobyouknow 2010-02-17 16:13:18

+2

答案:HttpClient 4.1-alpha1和HttpCore 4.1-alpha1從http:/ /hc.apache.org/downloads.cgi - 支持的Apache HttpComponents Java代碼。隨着這些,這個錯誤信息消失:) – therobyouknow 2010-02-17 16:37:46

0

如果你正在測試你的本地WAMP,你可能需要設置文件上傳的臨時文件夾。你可以在你的php.ini文件這樣做:

upload_tmp_dir = "c:\mypath\mytempfolder\" 

您需要授予文件夾的權限,以便上傳到發生 - 你需要授予的權限取決於您的操作系統。

+0

設置了tmp文件夾。上傳工作在服務器上,我用簡單的html表單測試了我的upload.php文件。 – 2009-07-01 07:49:05

+0

可以請你告訴我如何在java中編寫服務器代碼以接收httpclient請求 – Aswan 2010-04-21 08:35:25

3

正確的方法是使用多部分POST方法。有關客戶端的示例代碼,請參見here

對於PHP,有許多教程可用。這是我找到的first。我建議您首先使用html客戶端測試PHP代碼,然後嘗試java客戶端。

+0

我試圖使用你建議的方法,即HttpClient v.3.1,仍然is_uploaded_file返回false,但是這次$ _FILES數組填充了正確的數據,讓我更加困惑。 BTW。上傳工作在服務器上,我用簡單的html表單測試了我的upload.php文件。 – 2009-07-01 07:52:26

0

對於那些有一個很難實現的接受的答案(這需要org.apache.http.entity.mime.MultipartEntity),你可以使用org.apache.httpcomponents 4.2。* 在這種情況下,你必須明確安裝httpmime依賴,在我的情況:

<dependency> 
    <groupId>org.apache.httpcomponents</groupId> 
    <artifactId>httpmime</artifactId> 
    <version>4.2.5</version> 
</dependency> 
3

我遇到了同樣的問題,發現該文件名需要HttpClient的4.x到與PHP後端合作。 httpclient 3.x並非如此。

所以我的解決方案是在FileBody構造函數中添加一個名稱參數。 ContentBody cbFile = new FileBody(file,「image/jpeg」,「FILE_NAME」);

希望它有幫助。

29

對於那些試圖用MultipartEntity更新...

org.apache.http.entity.mime.MultipartEntity 4.3.1已被棄用。可以使用MultipartEntityBuilder創建HttpEntity對象。

File file = new File(); 

HttpEntity httpEntity = MultipartEntityBuilder.create() 
    .addBinaryBody("file", file, ContentType.create("image/jpeg"), file.getName()) 
    .build(); 

對於Maven用戶,該類可用於以下依賴關係(與fervisa的答案几乎相同,僅適用於更高版本)。

<dependency> 
    <groupId>org.apache.httpcomponents</groupId> 
    <artifactId>httpmime</artifactId> 
    <version>4.3.1</version> 
</dependency> 
0

有與郵寄的圖像,使用的Apache HTTP庫(很重要的是這裏的邊界加入我的連接,不會沒有它的工作),我工作的解決方案:

  ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); 
      byte[] imageBytes = baos.toByteArray(); 

      HttpClient httpclient = new DefaultHttpClient(); 
      HttpPost httpPost = new HttpPost(StaticData.AMBAJE_SERVER_URL + StaticData.AMBAJE_ADD_AMBAJ_TO_GROUP); 

      String boundary = "-------------" + System.currentTimeMillis(); 

      httpPost.setHeader("Content-type", "multipart/form-data; boundary="+boundary); 

      ByteArrayBody bab = new ByteArrayBody(imageBytes, "pic.png"); 
      StringBody sbOwner = new StringBody(StaticData.loggedUserId, ContentType.TEXT_PLAIN); 
      StringBody sbGroup = new StringBody("group", ContentType.TEXT_PLAIN); 

      HttpEntity entity = MultipartEntityBuilder.create() 
        .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) 
        .setBoundary(boundary) 
        .addPart("group", sbGroup) 
        .addPart("owner", sbOwner) 
        .addPart("image", bab) 
        .build(); 

      httpPost.setEntity(entity); 

      try { 
       HttpResponse response = httpclient.execute(httpPost); 
       ...then reading response 
1

啊哈你只需要添加一個名稱參數

FileBody constructor. ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME"); 

希望它有幫助。

2

A newer version example is here.

以下是原始代碼的副本:

/* 
* ==================================================================== 
* Licensed to the Apache Software Foundation (ASF) under one 
* or more contributor license agreements. See the NOTICE file 
* distributed with this work for additional information 
* regarding copyright ownership. The ASF licenses this file 
* to you under the Apache License, Version 2.0 (the 
* "License"); you may not use this file except in compliance 
* with the License. You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, 
* software distributed under the License is distributed on an 
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
* KIND, either express or implied. See the License for the 
* specific language governing permissions and limitations 
* under the License. 
* ==================================================================== 
* 
* This software consists of voluntary contributions made by many 
* individuals on behalf of the Apache Software Foundation. For more 
* information on the Apache Software Foundation, please see 
* <http://www.apache.org/>. 
* 
*/ 
package org.apache.http.examples.entity.mime; 

import java.io.File; 

import org.apache.http.HttpEntity; 
import org.apache.http.client.methods.CloseableHttpResponse; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.entity.ContentType; 
import org.apache.http.entity.mime.MultipartEntityBuilder; 
import org.apache.http.entity.mime.content.FileBody; 
import org.apache.http.entity.mime.content.StringBody; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClients; 
import org.apache.http.util.EntityUtils; 

/** 
* Example how to use multipart/form encoded POST request. 
*/ 
public class ClientMultipartFormPost { 

    public static void main(String[] args) throws Exception { 
     if (args.length != 1) { 
      System.out.println("File path not given"); 
      System.exit(1); 
     } 
     CloseableHttpClient httpclient = HttpClients.createDefault(); 
     try { 
      HttpPost httppost = new HttpPost("http://localhost:8080" + 
        "/servlets-examples/servlet/RequestInfoExample"); 

      FileBody bin = new FileBody(new File(args[0])); 
      StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN); 

      HttpEntity reqEntity = MultipartEntityBuilder.create() 
        .addPart("bin", bin) 
        .addPart("comment", comment) 
        .build(); 


      httppost.setEntity(reqEntity); 

      System.out.println("executing request " + httppost.getRequestLine()); 
      CloseableHttpResponse response = httpclient.execute(httppost); 
      try { 
       System.out.println("----------------------------------------"); 
       System.out.println(response.getStatusLine()); 
       HttpEntity resEntity = response.getEntity(); 
       if (resEntity != null) { 
        System.out.println("Response content length: " + resEntity.getContentLength()); 
       } 
       EntityUtils.consume(resEntity); 
      } finally { 
       response.close(); 
      } 
     } finally { 
      httpclient.close(); 
     } 
    } 

} 
1

我知道我遲到了,但下面是處理這個正確的方法,關鍵是要使用InputStreamBody代替FileBody上傳多部分文件。

try { 
     HttpClient httpclient = new DefaultHttpClient(); 
     HttpPost postRequest = new HttpPost("https://someserver.com/api/path/"); 
     postRequest.addHeader("Authorization",authHeader); 
     //don't set the content type here    
     //postRequest.addHeader("Content-Type","multipart/form-data"); 
     MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); 


     File file = new File(filePath); 
     FileInputStream fileInputStream = new FileInputStream(file); 
     reqEntity.addPart("parm-name", new InputStreamBody(fileInputStream,"image/jpeg","file_name.jpg")); 

     postRequest.setEntity(reqEntity); 
     HttpResponse response = httpclient.execute(postRequest); 

     }catch(Exception e) { 
      Log.e("URISyntaxException", e.toString()); 
    }