logo-cover-HttpClient 4.x POST请求(基础篇)

1.概述

在本教程中 - 我们将使用HttpClient 4进行POST - 首先使用授权,然后使用流畅的HttpClient API。最后 - 我们将讨论如何使用HttpClient上传文件

 

2.基本POST

首先,我们来看一个简单的例子,并使用HttpClient发送POST请求。

在以下示例中 - 我们将使用两个参数 - “ 用户名 ”和“ 密码 ” 进行POST :

@Test
public void whenPostRequestUsingHttpClient_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:

@Test
public void whenPostRequestWithAuthorizationUsingHttpClient_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进行POST

现在让我们看看如何使用HttpClient发送带有JSON正文的POST请求。

在以下示例中 - 我们将一些人员信息(id,name)作为JSON发送:

@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 ; 我们将发送带有两个参数“ 用户名 ”和“ 密码 ” 的请求:

@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多部分请求

现在 - 让我们发布一个Multipart Request - 在下面的例子中,我们将使用MultipartEntityBuilder发布文件,用户名和密码:

@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.获取文件上传 进度

最后 - 让我们看看如何使用HttpClient获得文件上传的进度。在下面的例子中 - 我们将扩展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 = 
     new ProgressEntityWrapper.ProgressListener() {
        @Override
        public void progress(float 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 ”

9.总结

在本教程中,我们演示了使用Apache HttpClient 4发送POST HTTP请求的最常用方式。

我们学习了如何使用授权发送POST请求,如何发布使用HttpClient fluent API以及如何上传文件并跟踪其进度。