Configurazione avanzata di HttpClient

1. Panoramica

In questo articolo, esamineremo l'utilizzo avanzato della libreria Apache HttpClient .

Esamineremo gli esempi di aggiunta di intestazioni personalizzate alle richieste HTTP e vedremo come configurare il client per autorizzare e inviare richieste tramite un server proxy.

Useremo Wiremock per lo stubbing del server HTTP. Se vuoi saperne di più su Wiremock, dai un'occhiata a questo articolo.

2. richiesta HTTP con un personalizzato User-Agent Header

Supponiamo di voler aggiungere un'intestazione User-Agent personalizzata a una richiesta HTTP GET. L' intestazione User-Agent contiene una stringa caratteristica che consente ai peer del protocollo di rete di identificare il tipo di applicazione, il sistema operativo e il fornitore del software o la versione del software dell'agente utente del software richiedente.

Prima di iniziare a scrivere il nostro client HTTP, dobbiamo avviare il nostro server fittizio incorporato:

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

Quando creiamo un'istanza HttpGet possiamo semplicemente usare un metodo setHeader () per passare un nome della nostra intestazione insieme al valore. Quell'intestazione verrà aggiunta a una richiesta HTTP:

String userAgent = "BaeldungAgent/1.0"; HttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("//localhost:8089/detail"); httpGet.setHeader(HttpHeaders.USER_AGENT, userAgent); HttpResponse response = httpClient.execute(httpGet); assertEquals(response.getStatusLine().getStatusCode(), 200);

Stiamo aggiungendo un'intestazione User-Agent e inviando la richiesta tramite un metodo execute () .

Quando viene inviata una richiesta GET per un URL / dettaglio con intestazione User-Agent che ha un valore uguale a "BaeldungAgent / 1.0", serviceMock restituirà 200 codice di risposta HTTP:

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

3. Invio di dati nel corpo della richiesta POST

Di solito, quando eseguiamo il metodo HTTP POST, vogliamo passare un'entità come corpo della richiesta. Quando si crea un'istanza di un oggetto HttpPost , possiamo aggiungere il corpo a quella richiesta utilizzando un metodo setEntity () :

String xmlBody = "1"; HttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost("//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);

Stiamo creando un'istanza StringEntity con un corpo in formato XML . È importante impostare l' intestazione Content-Type su " application / xml " per passare le informazioni al server sul tipo di contenuto che stiamo inviando. Quando il serviceMock riceve la richiesta POST con corpo XML, risponde con il codice di stato 200 OK:

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

4. Invio di richieste tramite un server proxy

Spesso, il nostro servizio web può trovarsi dietro un server proxy che esegue una logica aggiuntiva, memorizza nella cache risorse statiche, ecc. Quando creiamo il client HTTP e inviamo una richiesta a un servizio effettivo, non vogliamo occuparci di questo ogni richiesta HTTP.

Per testare questo scenario, avremo bisogno di avviare un altro server web incorporato:

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

Con due server incorporati, il primo servizio effettivo è sulla porta 8089 e un server proxy è in ascolto sulla porta 8090.

Stiamo configurando il nostro HttpClient per inviare tutte le richieste tramite proxy creando un DefaultProxyRoutePlanner che accetta il proxy dell'istanza HttpHost come argomento:

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

Il nostro server proxy sta reindirizzando tutte le richieste al servizio effettivo che ascolta sulla porta 8090. Alla fine del test, verifichiamo che la richiesta è stata inviata al nostro servizio effettivo tramite un proxy:

proxyMock.stubFor(get(urlMatching(".*")) .willReturn(aResponse().proxiedFrom("//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. Configurazione del client HTTP per l'autorizzazione tramite proxy

Estendendo l'esempio precedente, ci sono alcuni casi in cui il server proxy viene utilizzato per eseguire l'autorizzazione. In tale configurazione, un proxy può autorizzare tutte le richieste e passarle al server nascosto dietro un proxy.

Possiamo configurare HttpClient per inviare ogni richiesta tramite proxy, insieme all'intestazione di autorizzazione che verrà utilizzata per eseguire un processo di autorizzazione.

Supponiamo di avere un server proxy che autorizza un solo utente - " username_admin " , con una password " secret_password " .

Dobbiamo creare l' istanza BasicCredentialsProvider con le credenziali dell'utente che verrà autorizzato tramite proxy. Per fare in modo che HttpClient aggiunga automaticamente l' intestazione di autorizzazione con il valore appropriato, è necessario creare un HttpClientContext con le credenziali fornite e un BasicAuthCache che memorizza le credenziali:

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

Quando configuriamo il nostro HttpClient, le richieste al nostro servizio comporteranno l'invio di una richiesta tramite proxy con un'intestazione di autorizzazione per eseguire il processo di autorizzazione. Verrà impostato automaticamente in ogni richiesta.

Eseguiamo una richiesta effettiva al servizio:

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

La verifica di un metodo execute () su httpClient con la nostra configurazione conferma che una richiesta è passata attraverso un proxy con un'intestazione di autorizzazione :

proxyMock.stubFor(get(urlMatching("/private")) .willReturn(aResponse().proxiedFrom("//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. Conclusione

Questo articolo mostra come configurare Apache HttpClient per eseguire chiamate HTTP avanzate. Abbiamo visto come inviare richieste tramite un server proxy e come autorizzare tramite proxy.

L'implementazione di tutti questi esempi e frammenti di codice può essere trovata nel progetto GitHub: questo è un progetto Maven, quindi dovrebbe essere facile da importare ed eseguire così com'è.