用Java发送HTTP POST请求


294

让我们假设这个URL ...

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

(此处的ID需要在POST请求中发送)

我想将其发送id = 10到服务器的page.php,该服务器在POST方法中接受它。

如何在Java中执行此操作?

我尝试了这个:

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

但是我仍然不知道如何通过POST发送

Answers:


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进行了调用-就像我这样找到答案的人一样:)
Martin Lyne 2012年

1
@Juan(和Martin Lyne)感谢您的评论。我刚刚更新了答案。
mhshams

您修改后的答案是否仍使用hc.apache.org?
djangofan 2013年

@djangofan是的。在修订后的答案中也有指向apache-hc的链接。
mhshams

6
您应该添加导入的库
gouchaoer

191

在原始Java中,发送POST请求很容易。以a开头URL,我们不需要将其转换为URLConnectionusing url.openConnection();。之后,我们需要将其强制转换为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);

然后,我们需要声明要发送的内容:

发送一个简单的表格

来自http表单的普通POST具有定义明确的格式。我们需要将输入转换为以下格式:

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

我们也可以使用java发送json,这也很容易:

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 Post发送文件

由于格式更加复杂,发送文件被认为更具挑战性。我们也将增加对以字符串形式发送文件的支持,因为我们不想将文件完全缓冲到内存中。

为此,我们定义了一些辅助方法:

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需要获得两个附加的连字符,这些连字符不会在Content-Type中传输,因此boundaryBytes =(“-” + boundary +“ \ r \ n”)。get ...您还需要传输一次boundaryBytes在第一个字段或第一个字段之前,将被忽略!
Algoman

为什么out.write(finishBoundaryBytes);需要线路?http.connect();将执行发送POST,不是吗?
亚诺斯

16
“在原始Java中发送POST请求很容易。” 然后是数十行代码,与之类似requests.post('http://httpbin.org/post', data = {'key':'value'})的Python语言相比……我是Java的新手,所以对我来说,“易”一词的用法非常奇怪:)
Lynn

1
它比我认为是Java的情况要容易得多:)
shaahiin

神秘\ r \ n \ r \ n表示CRLF CRLF(回车+换行)。它会创建2x新行。第一行是结束当前行。第二行是在请求中将http标头与http正文区分开。HTTP是基于ASCII的协议。这是插入\ r \ n的规则。
米塔·贾斯汀

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完全失败。
Little Bobby Tables

5
以及如何设置2个发布数据?用冒号分隔,逗号?
吵闹的猫

10
encode(String)不推荐使用。您必须使用encode(String, String),它指定编码类型。范例:encode(rawData, "UTF-8")
sudo 2014年

3
您可能想在最后关注。这样可以确保请求已完成,并且服务器有机会处理响应:conn.getResponseCode();。
Szymon Jachim 2014年

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很有帮助。
杰伊

6
抱歉,您没有发现任何错误,而是介绍了它们。在无法处理异常的地方捕获异常是完全错误的,e.printStackTrace()无法处理任何事情。
maaartinus 2014年

java.net.ConnectException:连接超时:connect
kerZy Hart


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

我建议使用基于apache http api构建的http-request

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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.