Wysyłanie żądania HTTP POST w Javie


294

załóżmy, że ten adres URL ...

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

(Tutaj identyfikator należy wysłać w żądaniu POST)

Chcę wysłać id = 10do serwera page.php, który akceptuje go metodą POST.

Jak mogę to zrobić z poziomu Java?

Próbowałem tego:

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

Ale nadal nie mogę wymyślić, jak wysłać to za pomocą POST

Odpowiedzi:


339

Zaktualizowana odpowiedź:

Ponieważ niektóre klasy w oryginalnej odpowiedzi są przestarzałe w nowszej wersji komponentów HTTP Apache, publikuję tę aktualizację.

Nawiasem mówiąc, możesz uzyskać dostęp do pełnej dokumentacji, aby uzyskać więcej przykładów tutaj .

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
    }
}

Oryginalna odpowiedź:

Polecam używać Apache HttpClient. jest szybszy i łatwiejszy do wdrożenia.

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.

Aby uzyskać więcej informacji, sprawdź ten adres URL: http://hc.apache.org/


25
Po dłuższej próbie uzyskania odpowiedzi PostMethodwydaje się, że jest teraz wywoływany HttpPostzgodnie z stackoverflow.com/a/9242394/1338936 - tylko dla każdego, kto znalazł tę odpowiedź tak jak ja :)
Martin Lyne

1
@Juan (i Martin Lyne) dziękuję za komentarze. Właśnie zaktualizowałem odpowiedź.
mhshams,

Czy Twoja poprawiona odpowiedź nadal korzysta z hc.apache.org?
djangofan

@djangofan tak. w poprawionej odpowiedzi znajduje się również link do apache-hc.
mhshams,

6
powinieneś dodać importowane biblioteki
lib

191

Wysyłanie żądania POST jest łatwe w waniliowej Javie. Zaczynając od URL, musimy przekonwertować go na URLConnectionuse url.openConnection();. Następnie musimy rzucić go na a HttpURLConnection, abyśmy mogli uzyskać dostęp do jego setRequestMethod()metody i ustawić naszą metodę. W końcu mówimy, że będziemy wysyłać dane przez połączenie.

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);

Następnie musimy określić, co zamierzamy wysłać:

Wysyłanie prostego formularza

Normalny test POST pochodzący z formularza http ma dobrze zdefiniowany format. Musimy przekonwertować nasze dane wejściowe na ten format:

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;

Następnie możemy dołączyć treść formularza do żądania http z odpowiednimi nagłówkami i wysłać go.

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()

Wysyłanie JSON

Możemy również wysłać Json za pomocą java, jest to również łatwe:

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()

Pamiętaj, że różne serwery akceptują różne typy zawartości dla json, zobacz to pytanie.


Wysyłanie plików z postem Java

Wysyłanie plików można uznać za trudniejsze w obsłudze, ponieważ format jest bardziej złożony. Dodamy również obsługę wysyłania plików w postaci ciągu, ponieważ nie chcemy buforować pliku w całości do pamięci.

W tym celu definiujemy niektóre metody pomocnicze:

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));
}

Następnie możemy użyć tych metod, aby utworzyć wieloczęściowe żądanie postu w następujący sposób:

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
Ten post jest użyteczny, ale dość wadliwy. Uruchomienie go zajęło mi 2 dni. Aby więc działało, musisz zastąpić StandartCharsets.UTF8 StandardCharsets.UTF_8. boundaryBytes i finishBoundaryBytes muszą uzyskać dwa dodatkowe łączniki, które NIE są przesyłane w Content-Type, więc boundaryBytes = ("-" + boundary + "\ r \ n"). get ... Musisz także przesłać boundaryBytes raz ZANIM pierwsze pole lub pierwsze pole zostanie zignorowane!
Algoman

Dlaczego out.write(finishBoundaryBytes);linia potrzebuje? http.connect();wykona wysyłanie POST, prawda?
János

16
„Wysyłanie żądania POST jest łatwe w waniliowej Javie”. A potem dziesiątki linii kodu, w porównaniu do czegoś takiego jak requests.post('http://httpbin.org/post', data = {'key':'value'})w Pythonie… Jestem nowy w Javie, więc jest to dla mnie bardzo dziwne użycie słowa „łatwe” :)
Lynn

1
Jest to stosunkowo łatwiejsze niż się spodziewałem, biorąc pod uwagę, że jest to Java :)
shaahiin

enigmatyczny \ r \ n \ r \ n oznacza CRLF CRLF (powrót karetki + przesunięcie wiersza). Tworzy 2x nową linię. Pierwszą nową linią jest zakończenie obecnej linii. Druga linia to rozróżnienie nagłówka http od treści http w żądaniu. HTTP jest protokołem opartym na ASCII. To jest zasada wstawiania \ 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());

Ważne, aby zauważyć: użycie czegoś innego niż String.getBytes () nie działa. Na przykład użycie PrintWriter całkowicie zawodzi.
Małe tabele Bobby'ego,

5
i jak ustawić 2 dane postu? Oddziel je dwukropkiem, przecinek?
głośny kot

10
encode(String)jest przestarzałe. Musisz użyć encode(String, String), który określa typ kodowania. Przykład: encode(rawData, "UTF-8").
sudo

3
Możesz śledzić na końcu. Pozwoli to upewnić się, że żądanie zostało zakończone, a serwer ma szansę przetworzyć odpowiedź: conn.getResponseCode ();
Szymon Jachim

3
nie koduj całego łańcucha .. musisz zakodować tylko wartość każdego parametru
2914191

22

Pierwsza odpowiedź była świetna, ale musiałem dodać try / catch, aby uniknąć błędów kompilatora Java.
Miałem też problemy z ustaleniem, jak czytać HttpResponsebiblioteki Java.

Oto bardziej kompletny kod:

/*
 * 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 był pomocny.
Jay

6
Przepraszamy, ale nie złapałeś żadnych błędów, wprowadziłeś je. Łapanie wyjątków w miejscu, w którym nie można sobie z nimi poradzić, jest po prostu błędne i e.printStackTrace()niczego nie obsługuje.
maaartinus

java.net.ConnectException:
Przekroczono limit


5

najprostszy sposób na przesłanie parametrów za pomocą żądania postu:

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);

Uczyniłeś. teraz możesz użyć responsePOST. Uzyskaj treść odpowiedzi jako ciąg:

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

Wywołanie HttpURLConnection.setRequestMethod("POST")i HttpURLConnection.setDoOutput(true);właściwie tylko to drugie jest potrzebne, ponieważ POST staje się wówczas metodą domyślną.


it it HttpURLConnection.setRequestMethod () :)
Jose Diaz

1

Polecam użycie żądania http zbudowanego na 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();
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.