Erweiterte HttpClient-Konfiguration

Erweiterte HttpClient-Konfiguration

1. Überblick

In diesem Artikel werden wir uns mit der erweiterten Verwendung der ApacheHttpClient-Bibliothek befassen.

Wir werden uns die Beispiele zum Hinzufügen von benutzerdefinierten Headern zu HTTP-Anforderungen ansehen und sehen, wie der Client so konfiguriert wird, dass Anforderungen über einen Proxyserver autorisiert und gesendet werden.

Wir werden Wiremock zum Stubben des HTTP-Servers verwenden. Wenn Sie mehr über Wiremock erfahren möchten, lesen Siethis article.

2. HTTP-Anforderung mit einem benutzerdefiniertenUser-Agent-Header

Angenommen, wir möchten einer HTTP-GET-Anforderung einen benutzerdefiniertenUser-Agent-Header hinzufügen. Der Header vonUser-Agententhält eine charakteristische Zeichenfolge, mit der die Peers des Netzwerkprotokolls den Anwendungstyp, das Betriebssystem und den Softwareanbieter oder die Softwareversion des anfordernden Softwarebenutzeragenten identifizieren können.

Bevor wir unseren HTTP-Client schreiben, müssen wir unseren eingebetteten Mock-Server starten:

@Rule
public WireMockRule serviceMock = new WireMockRule(8089);

Wenn wir eineHttpGet-Instanz erstellen, können wir einfach einesetHeader()-Methode verwenden, um einen Namen unseres Headers zusammen mit dem Wert zu übergeben. Dieser Header wird zu einer HTTP-Anforderung hinzugefügt:

String userAgent = "exampleAgent/1.0";
HttpClient httpClient = HttpClients.createDefault();

HttpGet httpGet = new HttpGet("http://localhost:8089/detail");
httpGet.setHeader(HttpHeaders.USER_AGENT, userAgent);

HttpResponse response = httpClient.execute(httpGet);

assertEquals(response.getStatusLine().getStatusCode(), 200);

Wir fügen einenUser-Agent-Header hinzu und senden diese Anforderung über eineexecute()-Methode.

Wenn eine GET-Anforderung für eine URL/detail mit dem HeaderUser-Agent gesendet wird, deren Wert gleich "exampleAgent / 1.0" ist, gibtserviceMock 200 HTTP-Antwortcode zurück:

serviceMock.stubFor(get(urlEqualTo("/detail"))
  .withHeader("User-Agent", equalTo(userAgent))
  .willReturn(aResponse().withStatus(200)));

3. Senden von Daten im POST-Anforderungshauptteil

Normalerweise möchten wir beim Ausführen der HTTP-POST-Methode eine Entität als Anforderungshauptteil übergeben. Wenn Sie eine Instanz einesHttpPost-Objekts erstellen, können Sie den Body mit einersetEntity()-Methode zu dieser Anforderung hinzufügen:

String xmlBody = "1";
HttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://localhost:8089/person");
httpPost.setHeader("Content-Type", "application/xml");

StringEntity xmlEntity = new StringEntity(xmlBody);
httpPost.setEntity(xmlEntity);

HttpResponse response = httpClient.execute(httpPost);

assertEquals(response.getStatusLine().getStatusCode(), 200);

Wir erstellen eineStringEntity-Instanz mit einem Body imXML-Format. Es ist wichtig, den Header vonContent-Typeauf "application/xml" zu setzen, um Informationen über die Art des von uns gesendeten Inhalts an den Server zu übergeben. WennserviceMock die POST-Anforderung mit XML-Body empfängt, antwortet sie mit dem Statuscode 200 OK:

serviceMock.stubFor(post(urlEqualTo("/person"))
  .withHeader("Content-Type", equalTo("application/xml"))
  .withRequestBody(equalTo(xmlBody))
  .willReturn(aResponse().withStatus(200)));

4. Senden von Anfragen über einen Proxyserver

Häufig kann unser Webdienstbehind a proxy server sein, der zusätzliche Logik ausführt, statische Ressourcen zwischenspeichert usw. Wenn wir den HTTP-Client erstellen und eine Anfrage an einen tatsächlichen Dienst senden, möchten wir dies nicht bei jeder einzelnen HTTP-Anfrage behandeln.

Um dieses Szenario zu testen, müssen wir einen anderen eingebetteten Webserver starten:

@Rule
public WireMockRule proxyMock = new WireMockRule(8090);

Bei zwei eingebetteten Servern befindet sich der erste tatsächliche Dienst auf dem 8089-Port und ein Proxyserver überwacht den 8090-Port.

Wir konfigurieren unsereHttpClient so, dass alle Anforderungen über einen Proxy gesendet werden, indem wir einDefaultProxyRoutePlanner erstellen, das den Instanz-Proxy vonHttpHostals Argument verwendet:

HttpHost proxy = new HttpHost("localhost", 8090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
HttpClient httpclient = HttpClients.custom()
  .setRoutePlanner(routePlanner)
  .build();

Unser Proxy-Server leitet alle Anfragen an den tatsächlichen Dienst weiter, der den 8090-Port überwacht. Am Ende des Tests überprüfen wir, ob die Anfrage über einen Proxy an unseren tatsächlichen Service gesendet wurde:

proxyMock.stubFor(get(urlMatching(".*"))
  .willReturn(aResponse().proxiedFrom("http://localhost:8089/")));

serviceMock.stubFor(get(urlEqualTo("/private"))
  .willReturn(aResponse().withStatus(200)));

assertEquals(response.getStatusLine().getStatusCode(), 200);
proxyMock.verify(getRequestedFor(urlEqualTo("/private")));
serviceMock.verify(getRequestedFor(urlEqualTo("/private")));

5. Konfigurieren des HTTP-Clients für die Autorisierung über Proxy

In einigen Fällen wird der Proxy-Server zum Ausführen der Autorisierung verwendet, um das vorherige Beispiel zu erweitern. In einer solchen Konfiguration kann ein Proxy alle Anforderungen autorisieren und an den Server weiterleiten, der sich hinter einem Proxy befindet.

Wir können den HttpClient so konfigurieren, dass jede Anforderung über einen Proxy zusammen mit dem HeaderAuthorizationgesendet wird, der zum Ausführen eines Autorisierungsprozesses verwendet wird.

Angenommen, wir haben einen Proxyserver, der nur einen Benutzer autorisiert - "username_admin", mit einem Kennwort "secret_password".

Wir müssen die Instanz vonBasicCredentialsProvidermit den Anmeldeinformationen des Benutzers erstellen, der über den Proxy autorisiert wird. DamitHttpClient automatisch den HeaderAuthorization mit dem richtigen Wert hinzufügen, müssen Sie einHttpClientContext mit den angegebenen Anmeldeinformationen und einBasicAuthCache erstellen, in dem die Anmeldeinformationen gespeichert sind:

HttpHost proxy = new HttpHost("localhost", 8090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);

//Client credentials
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(proxy),
  new UsernamePasswordCredentials("username_admin", "secret_password"));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();

BasicScheme basicAuth = new BasicScheme();
authCache.put(proxy, basicAuth);
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credentialsProvider);
context.setAuthCache(authCache);

HttpClient httpclient = HttpClients.custom()
  .setRoutePlanner(routePlanner)
  .setDefaultCredentialsProvider(credentialsProvider)
  .build();

Wenn wir unsereHttpClient,einrichten, die Anfragen an unseren Service stellen, wird eine Anfrage über einen Proxy mit einemAuthorization-Header gesendet, um den Autorisierungsprozess durchzuführen. Es wird bei jeder Anfrage automatisch gesetzt.

Führen Sie eine tatsächliche Anforderung an den Dienst aus:

HttpGet httpGet = new HttpGet("http://localhost:8089/private");
HttpResponse response = httpclient.execute(httpGet, context);

Durch Überprüfen einerexecute()-Methode aufhttpClient mit unserer Konfiguration wird bestätigt, dass eine Anforderung einen Proxy mit einemAuthorization-Header durchlaufen hat:

proxyMock.stubFor(get(urlMatching("/private"))
  .willReturn(aResponse().proxiedFrom("http://localhost:8089/")));
serviceMock.stubFor(get(urlEqualTo("/private"))
  .willReturn(aResponse().withStatus(200)));

assertEquals(response.getStatusLine().getStatusCode(), 200);
proxyMock.verify(getRequestedFor(urlEqualTo("/private"))
  .withHeader("Authorization", containing("Basic")));
serviceMock.verify(getRequestedFor(urlEqualTo("/private")));

6. Fazit

Dieser Artikel zeigt, wie Sie die ApacheHttpClientfür die Ausführung erweiterter HTTP-Aufrufe konfigurieren. Wir haben gesehen, wie man Anfragen über einen Proxyserver sendet und wie man über einen Proxy autorisiert.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie inGitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.