การส่งคำขอ POST HTTP ใน Java


294

สมมติว่า URL นี้ ...

http://www.example.com/page.php?id=10            

(ต้องส่งรหัสที่นี่ในคำขอ POST)

ฉันต้องการส่งid = 10ไปยังเซิร์ฟเวอร์ของpage.phpซึ่งยอมรับในวิธีการโพสต์

ฉันจะทำสิ่งนี้จากภายใน Java ได้อย่างไร

ฉันลองสิ่งนี้:

URL aaa = new URL("http://www.example.com/page.php");
URLConnection ccc = aaa.openConnection();

แต่ฉันก็ยังนึกไม่ออกว่าจะส่งทางไปรษณีย์อย่างไร

คำตอบ:


339

อัปเดตคำตอบ:

เนื่องจากคลาสบางส่วนในคำตอบดั้งเดิมถูกคัดค้านใน Apache HTTP Components เวอร์ชันใหม่กว่าฉันกำลังโพสต์การอัปเดตนี้

โดยวิธีการที่คุณสามารถเข้าถึงเอกสารเต็มรูปแบบสำหรับตัวอย่างเพิ่มเติมที่นี่

HttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost("http://www.a-domain.com/foo/");

// Request parameters and other properties.
List<NameValuePair> params = new ArrayList<NameValuePair>(2);
params.add(new BasicNameValuePair("param-1", "12345"));
params.add(new BasicNameValuePair("param-2", "Hello!"));
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

//Execute and get the response.
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();

if (entity != null) {
    try (InputStream instream = entity.getContent()) {
        // do something useful
    }
}

คำตอบเดิม:

ฉันแนะนำให้ใช้ Apache HttpClient มันเร็วขึ้นและง่ายต่อการใช้งาน

HttpPost post = new HttpPost("http://jakarata.apache.org/");
NameValuePair[] data = {
    new NameValuePair("user", "joe"),
    new NameValuePair("password", "bloggs")
};
post.setRequestBody(data);
// execute method and handle any error responses.
...
InputStream in = post.getResponseBodyAsStream();
// handle response.

สำหรับข้อมูลเพิ่มเติมตรวจสอบ url นี้: http://hc.apache.org/


25
หลังจากพยายามในขณะที่จะได้รับในมือของฉันPostMethodดูเหมือนว่าตอนนี้จริง ๆ ที่เรียกว่าHttpPostเป็นต่อstackoverflow.com/a/9242394/1338936 - เพียงแค่สำหรับทุกคนในการหาคำตอบนี้เหมือนผม :)
มาร์ตินน์

1
@Juan (และ Martin Lyne) ขอบคุณสำหรับความคิดเห็น ฉันเพิ่งปรับปรุงคำตอบ
mhshams

คำตอบที่แก้ไขแล้วของคุณยังใช้ hc.apache.org อยู่หรือไม่?
djangofan

@dangangofan ใช่ มีลิงก์ไปยัง apache-hc ในคำตอบที่แก้ไขด้วย
mhshams

6
คุณควรเพิ่ม libs ที่นำเข้า
gouchaoer

191

การส่งคำขอ POST นั้นทำได้ง่าย ๆ ใน vanilla Java เริ่มต้นด้วยURLเราจำเป็นต้องแปลงเป็นใช้URLConnection url.openConnection();หลังจากนั้นเราต้องส่งไปที่ a HttpURLConnectionเพื่อให้เราสามารถเข้าถึงsetRequestMethod()วิธีการเพื่อตั้งค่าวิธีการของเรา ในที่สุดเราก็บอกว่าเรากำลังจะส่งข้อมูลผ่านการเชื่อมต่อ

URL url = new URL("https://www.example.com/login");
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection)con;
http.setRequestMethod("POST"); // PUT is another valid option
http.setDoOutput(true);

จากนั้นเราต้องระบุสิ่งที่เรากำลังจะส่ง:

ส่งแบบฟอร์มอย่างง่าย

POST ปกติที่มาจากฟอร์ม http มีรูปแบบที่กำหนดไว้อย่างดี เราจำเป็นต้องแปลงอินพุตของเราเป็นรูปแบบนี้:

Map<String,String> arguments = new HashMap<>();
arguments.put("username", "root");
arguments.put("password", "sjh76HSn!"); // This is a fake password obviously
StringJoiner sj = new StringJoiner("&");
for(Map.Entry<String,String> entry : arguments.entrySet())
    sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" 
         + URLEncoder.encode(entry.getValue(), "UTF-8"));
byte[] out = sj.toString().getBytes(StandardCharsets.UTF_8);
int length = out.length;

จากนั้นเราสามารถแนบเนื้อหาแบบฟอร์มของเราไปยังคำขอ http ด้วยส่วนหัวที่เหมาะสมและส่ง

http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.connect();
try(OutputStream os = http.getOutputStream()) {
    os.write(out);
}
// Do something with http.getInputStream()

กำลังส่ง JSON

เรายังสามารถส่ง json โดยใช้ java ซึ่งเป็นเรื่องง่าย:

byte[] out = "{\"username\":\"root\",\"password\":\"password\"}" .getBytes(StandardCharsets.UTF_8);
int length = out.length;

http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
http.connect();
try(OutputStream os = http.getOutputStream()) {
    os.write(out);
}
// Do something with http.getInputStream()

โปรดจำไว้ว่าเซิร์ฟเวอร์ต่างยอมรับเนื้อหาประเภทที่แตกต่างกันสำหรับ JSON ดูนี้คำถาม


การส่งไฟล์ด้วยโพสต์ java

การส่งไฟล์อาจมีความท้าทายมากขึ้นในการจัดการเนื่องจากรูปแบบนั้นซับซ้อนกว่า เราจะเพิ่มการสนับสนุนสำหรับการส่งไฟล์เป็นสตริงเนื่องจากเราไม่ต้องการบัฟเฟอร์ไฟล์ทั้งหมดในหน่วยความจำ

สำหรับสิ่งนี้เรากำหนดวิธีการช่วยเหลือบางอย่าง:

private void sendFile(OutputStream out, String name, InputStream in, String fileName) {
    String o = "Content-Disposition: form-data; name=\"" + URLEncoder.encode(name,"UTF-8") 
             + "\"; filename=\"" + URLEncoder.encode(filename,"UTF-8") + "\"\r\n\r\n";
    out.write(o.getBytes(StandardCharsets.UTF_8));
    byte[] buffer = new byte[2048];
    for (int n = 0; n >= 0; n = in.read(buffer))
        out.write(buffer, 0, n);
    out.write("\r\n".getBytes(StandardCharsets.UTF_8));
}

private void sendField(OutputStream out, String name, String field) {
    String o = "Content-Disposition: form-data; name=\"" 
             + URLEncoder.encode(name,"UTF-8") + "\"\r\n\r\n";
    out.write(o.getBytes(StandardCharsets.UTF_8));
    out.write(URLEncoder.encode(field,"UTF-8").getBytes(StandardCharsets.UTF_8));
    out.write("\r\n".getBytes(StandardCharsets.UTF_8));
}

จากนั้นเราสามารถใช้วิธีการเหล่านี้เพื่อสร้างคำขอโพสต์แบบหลายส่วนดังนี้

String boundary = UUID.randomUUID().toString();
byte[] boundaryBytes = 
           ("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8);
byte[] finishBoundaryBytes = 
           ("--" + boundary + "--").getBytes(StandardCharsets.UTF_8);
http.setRequestProperty("Content-Type", 
           "multipart/form-data; charset=UTF-8; boundary=" + boundary);

// Enable streaming mode with default settings
http.setChunkedStreamingMode(0); 

// Send our fields:
try(OutputStream out = http.getOutputStream()) {
    // Send our header (thx Algoman)
    out.write(boundaryBytes);

    // Send our first field
    sendField(out, "username", "root");

    // Send a seperator
    out.write(boundaryBytes);

    // Send our second field
    sendField(out, "password", "toor");

    // Send another seperator
    out.write(boundaryBytes);

    // Send our file
    try(InputStream file = new FileInputStream("test.txt")) {
        sendFile(out, "identification", file, "text.txt");
    }

    // Finish the request
    out.write(finishBoundaryBytes);
}


// Do something with http.getInputStream()

5
โพสต์นี้มีประโยชน์ แต่มีข้อบกพร่องค่อนข้างมาก ฉันใช้เวลา 2 วันในการทำงาน ดังนั้นเพื่อให้มันทำงานได้คุณต้องแทนที่ StandartCharsets.UTF8 ด้วย StandardCharsets.UTF_8 boundaryBytes และ finishBoundaryBytes จำเป็นต้องได้รับยัติภังค์เพิ่มเติมอีกสองตัวที่ไม่ได้รับการส่งผ่านในประเภทเนื้อหาดังนั้น boundaryBytes = ("-" + ขอบเขต + "\ r \ n") รับ ... คุณต้องส่งขอบเขตอีกครั้งด้วย ก่อนที่ฟิลด์แรกหรือฟิลด์แรกจะถูกละเว้น!
Algoman

ทำไมout.write(finishBoundaryBytes);ต้องมีสาย? http.connect();จะทำการส่ง POST ใช่ไหม
Janos

16
“ การส่งคำขอ POST นั้นทำได้ง่าย ๆ ใน vanilla Java” และจากนั้นหลายสิบบรรทัดของรหัสต่อไปนี้เมื่อเทียบกับสิ่งที่ต้องการrequests.post('http://httpbin.org/post', data = {'key':'value'})ในหลาม ... ฉันใหม่เพื่อ Java ดังนั้นนี่คือการใช้งานที่แปลกมากของคำว่า“ง่าย” ให้ฉัน :)
ลินน์

1
มันค่อนข้างง่ายกว่าสิ่งที่ผมคาดว่าจะพิจารณามัน Java :)
shaahiin

ปริศนา \ r \ n \ r \ n หมายถึง CRLF CRLF (carriage return + line feed) มันสร้างบรรทัดใหม่ 2x บรรทัดใหม่บรรทัดแรกคือการจบบรรทัดปัจจุบัน บรรทัดที่สองคือการแยกส่วนหัว http จากเนื้อหา http ในคำขอ HTTP เป็นโปรโตคอลที่ใช้ ASCII นี่คือกฎสำหรับการแทรก \ r \ n
Mitja Gustin

99
String rawData = "id=10";
String type = "application/x-www-form-urlencoded";
String encodedData = URLEncoder.encode( rawData, "UTF-8" ); 
URL u = new URL("http://www.example.com/page.php");
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty( "Content-Type", type );
conn.setRequestProperty( "Content-Length", String.valueOf(encodedData.length()));
OutputStream os = conn.getOutputStream();
os.write(encodedData.getBytes());

สิ่งสำคัญที่ควรสังเกต: การใช้สิ่งอื่นดังนั้น String.getBytes () จึงไม่ทำงาน ตัวอย่างเช่นการใช้ PrintWriter ล้มเหลวโดยสิ้นเชิง
ตาราง Bobby น้อย

5
และวิธีการตั้งค่า 2 โพสต์ข้อมูล? คั่นด้วยเครื่องหมายจุลภาคคั่นด้วยหรือไม่
แมวที่มีเสียงดัง

10
encode(String)เลิกใช้แล้ว คุณต้องใช้encode(String, String)ซึ่งระบุประเภทการเข้ารหัส ตัวอย่าง: encode(rawData, "UTF-8").
sudo

3
คุณอาจต้องการติดตามในตอนท้าย สิ่งนี้จะทำให้แน่ใจว่าการร้องขอเสร็จสิ้นและเซิร์ฟเวอร์มีโอกาสประมวลผลการตอบกลับ: conn.getResponseCode ();
Szymon Jachim

3
อย่าเข้ารหัสสตริงทั้งหมด .. คุณต้องเข้ารหัสเฉพาะค่าของพารามิเตอร์แต่ละตัว
user2914191

22

คำตอบแรกดีมาก แต่ฉันต้องเพิ่ม try / catch เพื่อหลีกเลี่ยงข้อผิดพลาดของคอมไพเลอร์ Java
นอกจากนี้ฉันมีปัญหาในการคิดวิธีการอ่านHttpResponseด้วยห้องสมุด Java

นี่คือรหัสที่สมบูรณ์มากขึ้น:

/*
 * Create the POST request
 */
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://example.com/");
// Request parameters and other properties.
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("user", "Bob"));
try {
    httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
} catch (UnsupportedEncodingException e) {
    // writing error to Log
    e.printStackTrace();
}
/*
 * Execute the HTTP Request
 */
try {
    HttpResponse response = httpClient.execute(httpPost);
    HttpEntity respEntity = response.getEntity();

    if (respEntity != null) {
        // EntityUtils to get the response content
        String content =  EntityUtils.toString(respEntity);
    }
} catch (ClientProtocolException e) {
    // writing exception to log
    e.printStackTrace();
} catch (IOException e) {
    // writing exception to log
    e.printStackTrace();
}

EntityUtils มีประโยชน์
Jay

6
ขออภัยคุณไม่พบข้อผิดพลาดใด ๆ เลย การจับข้อยกเว้นในสถานที่ที่คุณไม่สามารถจัดการได้เป็นเรื่องธรรมดาและe.printStackTrace()ไม่จัดการอะไรเลย
maaartinus

java.net.ConnectException: การเชื่อมต่อหมดเวลา: เชื่อมต่อ
kerZy Hart

17

วิธีง่ายๆในการใช้ Apache HTTP Components คือ

Request.Post("http://www.example.com/page.php")
            .bodyForm(Form.form().add("id", "10").build())
            .execute()
            .returnContent();

ดูที่Fluent API


3
เพียงเพื่อความสะดวก การตั้งค่าการอ้างอิง / ข้อมูล: hc.apache.org/httpcomponents-client-4.5.x/httpclient/ …และhc.apache.org/httpcomponents-client-4.5.x/fluent-hc/…
Jaroslav Záruba

5

วิธีที่ง่ายที่สุดในการส่งพารามิเตอร์ด้วยคำขอโพสต์:

String postURL = "http://www.example.com/page.php";

HttpPost post = new HttpPost(postURL);

List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", "10"));

UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, "UTF-8");
post.setEntity(ent);

HttpClient client = new DefaultHttpClient();
HttpResponse responsePOST = client.execute(post);

คุณทำไปแล้ว responsePOSTตอนนี้คุณสามารถใช้ รับเนื้อหาการตอบสนองเป็นสตริง:

BufferedReader reader = new BufferedReader(new  InputStreamReader(responsePOST.getEntity().getContent()), 2048);

if (responsePOST != null) {
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(" line : " + line);
        sb.append(line);
    }
    String getResponseString = "";
    getResponseString = sb.toString();
//use server output getResponseString as string value.
}

1

การโทรHttpURLConnection.setRequestMethod("POST")และที่HttpURLConnection.setDoOutput(true);จริงแล้วจำเป็นต้องใช้หลังเท่านั้นเนื่องจาก POST จะกลายเป็นวิธีการเริ่มต้น


มัน HttpURLConnection.setRequestMethod () :)
Jose Diaz

1

ฉันขอแนะนำให้ใช้การร้องขอ http ที่สร้างขึ้นบน apache http api

HttpRequest<String> httpRequest = HttpRequestBuilder.createPost("http://www.example.com/page.php", String.class)
.responseDeserializer(ResponseDeserializer.ignorableDeserializer()).build();

public void send(){
   String response = httpRequest.execute("id", "10").get();
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.