ฉันจะสร้างคำขอ POST แบบหลายส่วน / แบบฟอร์มโดยใช้ Java ได้อย่างไร


97

ในสมัยของ Apache Commons HttpClient เวอร์ชัน 3.x การสร้างคำขอ POST แบบหลายส่วน / แบบฟอร์มเป็นไปได้ ( ตัวอย่างจากปี 2004 ) แต่น่าเสียดายที่นี้เป็นไปไม่ได้ในรุ่น 4.0 ของ HttpClient

สำหรับกิจกรรมหลักของเรา "HTTP" หลายส่วนอยู่นอกขอบเขต เราชอบที่จะใช้รหัสหลายส่วนที่ดูแลโดยโครงการอื่นที่อยู่ในขอบเขต แต่ฉันไม่ทราบเรื่องใด ๆ เราพยายามย้ายรหัสหลายส่วนไปยังตัวแปลงสัญญาณคอมมอนส์เมื่อสองสามปีก่อน แต่ฉันไม่ได้ถอดที่นั่น เมื่อเร็ว ๆ นี้ Oleg ได้กล่าวถึงโครงการอื่นที่มีรหัสการแยกวิเคราะห์หลายส่วนและอาจสนใจรหัสการจัดรูปแบบหลายส่วนของเรา ฉันไม่ทราบสถานะปัจจุบันของสิ่งนั้น ( http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html )

มีใครทราบเกี่ยวกับไลบรารี Java ที่อนุญาตให้ฉันเขียนไคลเอ็นต์ HTTP ที่สามารถสร้างคำขอ POST แบบหลายส่วน / แบบฟอร์มได้หรือไม่

พื้นหลัง: ฉันต้องการที่จะใช้API ระยะไกลของ Zoho Writer


ดูเพิ่มเติม - bayou.io/release/1.0/docs/http/Http_Client.html
ZhongYu

คำตอบ:


152

เราใช้ HttpClient 4.x เพื่อโพสต์ไฟล์หลายส่วน

อัปเดต : ตั้งแต่HttpClient 4.3บางคลาสได้เลิกใช้งานแล้ว นี่คือรหัสที่มี API ใหม่:

CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost uploadFile = new HttpPost("...");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody("field1", "yes", ContentType.TEXT_PLAIN);

// This attaches the file to the POST:
File f = new File("[/path/to/upload]");
builder.addBinaryBody(
    "file",
    new FileInputStream(f),
    ContentType.APPLICATION_OCTET_STREAM,
    f.getName()
);

HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
CloseableHttpResponse response = httpClient.execute(uploadFile);
HttpEntity responseEntity = response.getEntity();

ด้านล่างนี้คือข้อมูลโค้ดดั้งเดิมที่เลิกใช้งาน HttpClient 4.0 API :

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);

FileBody bin = new FileBody(new File(fileName));
StringBody comment = new StringBody("Filename: " + fileName);

MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("bin", bin);
reqEntity.addPart("comment", comment);
httppost.setEntity(reqEntity);

HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();

63
อ่าสิ่งที่มีหลายส่วนถูกย้ายไปที่ org.apache แล้ว อาจมีการกล่าวถึงบางแห่ง: /

ฉันลองใช้รหัสที่อัปเดตของคุณซึ่งใช้งานได้ดีกับไฟล์ขนาดเล็ก แต่ใช้กับไฟล์ขนาดใหญ่ไม่ได้ คุณช่วยฉันด้วยคำถาม
ไหม

สวัสดี ZZ ฉันได้ทำการเปลี่ยนแปลงข้างต้นในรหัสของฉันแล้วอย่างไรก็ตามตอนนี้ฉันกำลังประสบปัญหาใหม่ - ปลายทาง REST ของฉันไม่ยอมรับคำขอ โดยคาดหวังพารามิเตอร์ต่อไปนี้: ~ @ PathVariable final String id, @RequestParam ("image") final MultipartFile image, @RequestParam ("l") final String l, @RequestParam ("lo") final String lo, @RequestParam (" bac ") final String bac, @RequestParam (" cac ") final String cac, @RequestParam (" m ") final String m ... ก่อนหน้านี้คำขอกำลังได้รับการยอมรับ แต่ตอนนี้ฉันได้รับข้อผิดพลาด 500 มีความคิดว่าเหตุใดจึงอาจเกิดขึ้น
Logan

ฉันแก้ไขคำตอบเพื่อให้ตัวอย่างโค้ดไม่เลื่อนในแนวนอนอีกต่อไป - การเลื่อนทำให้ฉันพลาดพารามิเตอร์สุดท้ายที่สำคัญเมื่อฉันพยายามใช้ในงานของฉันเอง
G.Sylvie Davies

ต่อไปนี้คือการพึ่งพา Maven สำหรับคำตอบที่อัปเดต <dependency> <groupId> org.apache.httpcomponents </groupId> <artifactId> httpclient </artifactId> <version> 4.3.6 </version> </dependency> <! - mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -> <dependency> <groupId> org.apache.httpcomponents </groupId> <artifactId> httpmime </artifactId> <version> 4.3.6 </version> < / dependency>
Wazime

39

นี่คือการพึ่งพา Maven ที่ฉันมี

รหัส Java:

HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);

FileBody uploadFilePart = new FileBody(uploadFile);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("upload-file", uploadFilePart);
httpPost.setEntity(reqEntity);

HttpResponse response = httpclient.execute(httpPost);

การพึ่งพา Maven ใน pom.xml:

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.0.1</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpmime</artifactId>
  <version>4.0.1</version>
  <scope>compile</scope>
</dependency>

1
คุณจะต้องใช้ httpcore เช่นกันอย่างน้อยใน 4.2 สำหรับHttpEntityชั้นเรียน
alalonde

19

หากขนาดของ JARs มีความสำคัญ (เช่นในกรณีของแอพเพล็ต) เราสามารถใช้ httpmime กับ java.net ได้โดยตรง HTTPURLConnection แทน HttpClient

httpclient-4.2.4:      423KB
httpmime-4.2.4:         26KB
httpcore-4.2.4:        222KB
commons-codec-1.6:     228KB
commons-logging-1.1.1:  60KB
Sum:                   959KB

httpmime-4.2.4:         26KB
httpcore-4.2.4:        222KB
Sum:                   248KB

รหัส:

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");

FileBody fileBody = new FileBody(new File(fileName));
MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.STRICT);
multipartEntity.addPart("file", fileBody);

connection.setRequestProperty("Content-Type", multipartEntity.getContentType().getValue());
OutputStream out = connection.getOutputStream();
try {
    multipartEntity.writeTo(out);
} finally {
    out.close();
}
int status = connection.getResponseCode();
...

การพึ่งพาใน pom.xml:

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

FileBody นี้มาจากไหน? มีวิธี (ง่าย ๆ ) ที่จะไม่ใช้ apace.httpcomponents หรือไม่?
จูเนียร์

6

ใช้รหัสนี้เพื่ออัปโหลดภาพหรือไฟล์อื่น ๆ ไปยังเซิร์ฟเวอร์โดยใช้โพสต์ในหลายส่วน

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;

public class SimplePostRequestTest {

    public static void main(String[] args) throws UnsupportedEncodingException, IOException {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost("http://192.168.0.102/uploadtest/upload_photo");

        try {
            FileBody bin = new FileBody(new File("/home/ubuntu/cd.png"));
            StringBody id = new StringBody("3");
            MultipartEntity reqEntity = new MultipartEntity();
            reqEntity.addPart("upload_image", bin);
            reqEntity.addPart("id", id);
            reqEntity.addPart("image_title", new StringBody("CoolPic"));

            httppost.setEntity(reqEntity);
            System.out.println("Requesting : " + httppost.getRequestLine());
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String responseBody = httpclient.execute(httppost, responseHandler);
            System.out.println("responseBody : " + responseBody);

        } catch (ClientProtocolException e) {

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

}

ต้องใช้ไฟล์ด้านล่างเพื่ออัปโหลด

ไลบรารีอยู่ httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jarและ commons-logging-1.1.1.jarอยู่ใน classpath


4

คุณยังสามารถใช้REST Assuredซึ่งสร้างบนไคลเอนต์ HTTP ง่ายมาก:

given().multiPart(new File("/somedir/file.bin")).when().post("/fileUpload");

จะถือว่าชื่อควบคุมเรียกว่า "ไฟล์" หากคุณมีชื่อควบคุมอื่นคุณต้องระบุ: multiPart("controlName", new File("/somedir/file.bin"))ดูgithub.com/rest-assured/rest-assured/wiki/…
asmaier

REST Assured มี API ที่ยอดเยี่ยมและรองรับคุณสมบัติมากมาย ทำงานด้วยก็มีความสุข แต่เพื่อความเป็นธรรมคุณควรกล่าวถึงว่าเนื่องจากขั้นตอนการอุ่นเครื่องบางอย่างคุณอาจพบว่าประสิทธิภาพลดลงในการโทรครั้งแรก คุณสามารถค้นหาข้อมูลเพิ่มเติมได้ทางอินเทอร์เน็ตเช่นที่นี่sqa.stackexchange.com/questions/39532/…
user1053510

REST Assured เป็นไลบรารีที่ยอดเยี่ยม แต่ได้รับการออกแบบมาสำหรับการทดสอบ Web API และฉันไม่คิดว่ามันเป็นเครื่องมือที่เหมาะสมในการโทร HTTP ในรหัสการผลิตแม้ว่าแน่นอนว่าจะใช้ไลบรารีพื้นฐานเดียวกันก็ตาม
Ranil Wijeyratne

3

นี่คือโซลูชันที่ไม่ต้องใช้ไลบรารีใด ๆ

รูทีนนี้ส่งไฟล์ทุกไฟล์ในไดเร็กทอรีd:/data/mpf10ไปที่urlToConnect


String boundary = Long.toHexString(System.currentTimeMillis());
URLConnection connection = new URL(urlToConnect).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
    writer = new PrintWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
    File dir = new File("d:/data/mpf10");
    for (File file : dir.listFiles()) {
        if (file.isDirectory()) {
            continue;
        }
        writer.println("--" + boundary);
        writer.println("Content-Disposition: form-data; name=\"" + file.getName() + "\"; filename=\"" + file.getName() + "\"");
        writer.println("Content-Type: text/plain; charset=UTF-8");
        writer.println();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
            for (String line; (line = reader.readLine()) != null;) {
                writer.println(line);
            }
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }
    writer.println("--" + boundary + "--");
} finally {
    if (writer != null) writer.close();
}
// Connection is lazily executed whenever you request any status.
int responseCode = ((HttpURLConnection) connection).getResponseCode();
// Handle response

2

httpcomponents-client-4.0.1ทำงานให้ฉัน อย่างไรก็ตามฉันต้องเพิ่ม jar ภายนอกapache-mime4j-0.6.jar ( org.apache.james.mime4j ) มิฉะนั้น reqEntity.addPart("bin", bin);จะไม่รวบรวม ตอนนี้มันทำงานอย่างมีเสน่ห์


2

ผมพบว่าตัวอย่างนี้ในของ Apache Quickstart คู่มือ สำหรับเวอร์ชัน 4.5:

/**
 * 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();
        }
    }
}

0

เรามีการใช้งาน java แบบเพียว ๆ ของการส่งแบบฟอร์มหลายส่วนโดยไม่ต้องใช้การอ้างอิงภายนอกหรือไลบรารีภายนอก jdk อ้างอิงhttps://github.com/atulsm/https-multipart-purejava/blob/master/src/main/java/com/atul/MultipartPure.java

private static String body = "{\"key1\":\"val1\", \"key2\":\"val2\"}";
private static String subdata1 = "@@ -2,3 +2,4 @@\r\n";
private static String subdata2 = "<data>subdata2</data>";

public static void main(String[] args) throws Exception{        
    String url = "https://" + ip + ":" + port + "/dataupload";
    String token = "Basic "+ Base64.getEncoder().encodeToString((userName+":"+password).getBytes());

    MultipartBuilder multipart = new MultipartBuilder(url,token);       
    multipart.addFormField("entity", "main", "application/json",body);
    multipart.addFormField("attachment", "subdata1", "application/octet-stream",subdata1);
    multipart.addFormField("attachment", "subdata2", "application/octet-stream",subdata2);        
    List<String> response = multipart.finish();         
    for (String line : response) {
        System.out.println(line);
    }
}

0

รหัสของฉันโพสต์ไฟล์หลายส่วนไปยังเซิร์ฟเวอร์

  public static HttpResponse doPost(
    String host,
    String path,
    String method,
    MultipartFile multipartFile
  ) throws IOException
  {

    HttpClient httpClient = wrapClient(host);
    HttpPost httpPost = new HttpPost(buildUrl(host, path));

    if (multipartFile != null) {

      HttpEntity httpEntity;

      ContentBody contentBody;
      contentBody = new ByteArrayBody(multipartFile.getBytes(), multipartFile.getOriginalFilename());
      httpEntity = MultipartEntityBuilder.create()
                                         .addPart("nameOfMultipartFile", contentBody)
                                         .build();

      httpPost.setEntity(httpEntity);

    }
    return httpClient.execute(httpPost);
  }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.