Apache HttpClient 4发送 POST HTTP 请求
1. 概述
在本教程中,我们将使用HttpClient 4进行 POST ,首先使用授权,然后使用流利的 HttpClient API。
最后,我们将讨论如何使用 HttpClient 上传文件。
2. 基本 POST
首先,让我们看一个简单的例子,并使用HttpClient发送一个 POST 请求。
我们将使用两个参数“username”和“password”进行 POST:
@Test
public void whenSendPostRequestUsingHttpClient_thenCorrect()
throws ClientProtocolException, IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://www.example.com");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "John"));
params.add(new BasicNameValuePair("password", "pass"));
httpPost.setEntity(new UrlEncodedFormEntity(params));
CloseableHttpResponse response = client.execute(httpPost);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
client.close();
}
请注意我们如何使用NameValuePair列表在POST 请求中包含参数。
3. POST 授权
接下来,让我们看看如何使用HttpClient使用身份验证凭据进行 POST 。
在以下示例中,我们将通过添加授权标头向使用基本身份验证保护的 URL 发送 POST 请求:
@Test
public void whenSendPostRequestWithAuthorizationUsingHttpClient_thenCorrect()
throws ClientProtocolException, IOException, AuthenticationException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://www.example.com");
httpPost.setEntity(new StringEntity("test post"));
UsernamePasswordCredentials creds
= new UsernamePasswordCredentials("John", "pass");
httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null));
CloseableHttpResponse response = client.execute(httpPost);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
client.close();
}
4. 使用 JSON 发布
现在让我们看看如何使用HttpClient发送带有 JSON 正文的 POST 请求。
在以下示例中,我们将以JSON 格式发送一些人员信息(id、name ):
@Test
public void whenPostJsonUsingHttpClient_thenCorrect()
throws ClientProtocolException, IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://www.example.com");
String json = "{"id":1,"name":"John"}";
StringEntity entity = new StringEntity(json);
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
CloseableHttpResponse response = client.execute(httpPost);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
client.close();
}
请注意我们如何使用StringEntity来设置请求的正文。
我们还将ContentType标头设置为application/json 以向服务器提供有关我们正在发送的内容表示的必要信息。
5. 使用HttpClient Fluent API POST
接下来,让我们使用HttpClient Fluent API 进行 POST。
我们将发送一个带有两个参数的请求,“username”和“password”:
@Test
public void whenPostFormUsingHttpClientFluentAPI_thenCorrect()
throws ClientProtocolException, IOException {
HttpResponse response = Request.Post("http://www.example.com").bodyForm(
Form.form().add("username", "John").add("password", "pass").build())
.execute().returnResponse();
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
}
6. POST 多部分请求
现在让我们发布一个多部分请求。
我们将使用MultipartEntityBuilder发布file、username和password:
@Test
public void whenSendMultipartRequestUsingHttpClient_thenCorrect()
throws ClientProtocolException, IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://www.example.com");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody("username", "John");
builder.addTextBody("password", "pass");
builder.addBinaryBody(
"file", new File("test.txt"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
CloseableHttpResponse response = client.execute(httpPost);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
client.close();
}
7. 使用HttpClient上传文件
接下来,让我们看看如何使用HttpClient上传文件。
我们将使用MultipartEntityBuilder上传“ test.txt ”文件:
@Test
public void whenUploadFileUsingHttpClient_thenCorrect()
throws ClientProtocolException, IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://www.example.com");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody(
"file", new File("test.txt"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
CloseableHttpResponse response = client.execute(httpPost);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
client.close();
}
8. 获取file上传进度
最后,让我们看看如何使用HttpClient获取file上传的进度。
在以下示例中,我们将扩展HttpEntityWrapper以了解上传过程。 首先,这是上传方法:
@Test
public void whenGetUploadFileProgressUsingHttpClient_thenCorrect()
throws ClientProtocolException, IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://www.example.com");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody(
"file", new File("test.txt"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
HttpEntity multipart = builder.build();
ProgressEntityWrapper.ProgressListener pListener =
percentage -> assertFalse(Float.compare(percentage, 100) > 0);
httpPost.setEntity(new ProgressEntityWrapper(multipart, pListener));
CloseableHttpResponse response = client.execute(httpPost);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
client.close();
}
我们还将添加接口ProgressListener使我们能够观察上传进度:
public static interface ProgressListener {
void progress(float percentage);
}
这是我们的HttpEntityWrapper的扩展版本, “ ProgressEntityWrapper ”:
public class ProgressEntityWrapper extends HttpEntityWrapper {
private ProgressListener listener;
public ProgressEntityWrapper(HttpEntity entity, ProgressListener listener) {
super(entity);
this.listener = listener;
}
@Override
public void writeTo(OutputStream outstream) throws IOException {
super.writeTo(new CountingOutputStream(outstream, listener, getContentLength()));
}
}
这是FilterOutputStream 的扩展版本,“ CountingOutputStream ”:
public static class CountingOutputStream extends FilterOutputStream {
private ProgressListener listener;
private long transferred;
private long totalBytes;
public CountingOutputStream(
OutputStream out, ProgressListener listener, long totalBytes) {
super(out);
this.listener = listener;
transferred = 0;
this.totalBytes = totalBytes;
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
transferred += len;
listener.progress(getCurrentProgress());
}
@Override
public void write(int b) throws IOException {
out.write(b);
transferred++;
listener.progress(getCurrentProgress());
}
private float getCurrentProgress() {
return ((float) transferred / totalBytes) * 100;
}
}
注意:
- 当将FilterOutputStream扩展为“ CountingOutputStream ”时,我们重写了*write()*方法来计算写入(传输)的字节数
- 当将HttpEntityWrapper扩展为“ ProgressEntityWrapper ”时,我们将覆盖writeTo()方法以使用我们的“CountingOutputStream”