1. Gambaran keseluruhan
Dalam artikel ini, kita akan melihat penggunaan lanjutan perpustakaan Apache HttpClient .
Kami akan melihat contoh penambahan tajuk khusus untuk permintaan HTTP, dan kami akan melihat cara mengkonfigurasi klien untuk memberi kuasa dan menghantar permintaan melalui pelayan proksi.
Kami akan menggunakan Wiremock untuk membendung pelayan HTTP. Sekiranya anda ingin membaca lebih lanjut mengenai Wiremock, lihat artikel ini.
2. Permintaan HTTP Dengan Header Ejen Pengguna Tersuai
Katakan bahawa kami ingin menambahkan header User-Agent tersuai pada permintaan HTTP GET. The User-Agent header mengandungi rentetan ciri yang membolehkan rakan-rakan protokol rangkaian untuk mengenalpasti jenis aplikasi, sistem operasi, dan vendor perisian atau versi perisian ejen perisian pengguna yang meminta.
Sebelum mula menulis klien HTTP, kita perlu memulakan pelayan tiruan tertanam:
@Rule public WireMockRule serviceMock = new WireMockRule(8089);
Semasa kita membuat instance HttpGet, kita hanya dapat menggunakan kaedah setHeader () untuk meneruskan nama header kita bersama dengan nilainya. Tajuk itu akan ditambahkan ke permintaan 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);
Kami menambah tajuk User-Agent dan menghantar permintaan itu melalui kaedah execute () .
Apabila permintaan GET dikirim untuk URL / perincian dengan header User-Agent yang memiliki nilai sama dengan "BaeldungAgent / 1.0" maka serviceMock akan mengembalikan 200 kod respons HTTP:
serviceMock.stubFor(get(urlEqualTo("/detail")) .withHeader("User-Agent", equalTo(userAgent)) .willReturn(aResponse().withStatus(200)));
3. Menghantar Data di Badan Permintaan POST
Biasanya, ketika kita menjalankan kaedah HTTP POST, kita ingin meneruskan entiti sebagai badan permintaan. Semasa membuat contoh objek HttpPost , kita dapat menambahkan isi permintaan tersebut menggunakan kaedah 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);
Kami membuat instance StringEntity dengan badan yang dalam format XML . Penting untuk menetapkan tajuk Jenis Konten ke " aplikasi / xml " untuk menyampaikan maklumat kepada pelayan mengenai jenis kandungan yang kami kirimkan. Apabila serviceMock menerima permintaan POST dengan badan XML, ia bertindak balas dengan kod status 200 OK:
serviceMock.stubFor(post(urlEqualTo("/person")) .withHeader("Content-Type", equalTo("application/xml")) .withRequestBody(equalTo(xmlBody)) .willReturn(aResponse().withStatus(200)));
4. Menghantar Permintaan melalui Pelayan Proksi
Selalunya, perkhidmatan web kami berada di belakang pelayan proksi yang melakukan beberapa logik tambahan, cache sumber statik, dan lain-lain. Semasa kami membuat Klien HTTP dan menghantar permintaan ke perkhidmatan sebenar, kami tidak mahu menghadapinya pada setiap permintaan HTTP.
Untuk menguji senario ini, kita perlu memulakan pelayan web terbenam yang lain:
@Rule public WireMockRule proxyMock = new WireMockRule(8090);
Dengan dua pelayan terbenam, perkhidmatan sebenar pertama adalah pada port 8089 dan pelayan proksi mendengar di port 8090.
Kami mengkonfigurasi HttpClient kami untuk menghantar semua permintaan melalui proksi dengan membuat DefaultProxyRoutePlanner yang mengambil proksi instance HttpHost sebagai argumen:
HttpHost proxy = new HttpHost("localhost", 8090); DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); HttpClient httpclient = HttpClients.custom() .setRoutePlanner(routePlanner) .build();
Pelayan proksi kami mengalihkan semua permintaan ke perkhidmatan sebenar yang mendengar pada port 8090. Pada akhir ujian, kami mengesahkan bahawa permintaan telah dihantar ke perkhidmatan sebenar kami melalui proksi:
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. Mengkonfigurasi Pelanggan HTTP untuk Memberi Kuasa melalui Proksi
Memperluas contoh sebelumnya, terdapat beberapa kes apabila pelayan proksi digunakan untuk menjalankan kebenaran. Dalam konfigurasi seperti itu, proksi dapat membenarkan semua permintaan dan meneruskannya ke pelayan yang tersembunyi di sebalik proksi.
Kami dapat mengkonfigurasi HttpClient untuk mengirim setiap permintaan melalui proksi, bersama dengan tajuk Pengesahan yang akan digunakan untuk melakukan proses otorisasi .
Anggaplah kita mempunyai pelayan proksi yang membenarkan hanya satu pengguna - " username_admin " , dengan kata laluan " secret_password " .
Kita perlu membuat instance BasicCredentialsProvider dengan tauliah pengguna yang akan diberi kuasa melalui proksi. Untuk menjadikan HttpClient secara automatik menambahkan tajuk Pengesahan dengan nilai yang tepat, kita perlu membuat HttpClientContext dengan kelayakan yang disediakan dan BasicAuthCache yang menyimpan kelayakan:
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();
Apabila kami mendirikan kami HttpClient, membuat permintaan untuk perkhidmatan kami akan mengakibatkan menghantar permintaan melalui proksi dengan Kebenaran header untuk melaksanakan proses pengesahan. Itu akan ditetapkan dalam setiap permintaan secara automatik.
Mari laksanakan permintaan sebenar ke perkhidmatan:
HttpGet httpGet = new HttpGet("//localhost:8089/private"); HttpResponse response = httpclient.execute(httpGet, context);
Mengesahkan kaedah execute () pada httpClient dengan konfigurasi kami mengesahkan bahawa permintaan melalui proksi dengan tajuk Authorization :
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. Kesimpulannya
Artikel ini menunjukkan cara mengkonfigurasi Apache HttpClient untuk melakukan panggilan HTTP lanjutan. Kami melihat cara menghantar permintaan melalui pelayan proksi dan cara memberi kebenaran melalui proksi.
Pelaksanaan semua contoh dan coretan kod ini terdapat dalam projek GitHub - ini adalah projek Maven, jadi mudah untuk diimport dan dijalankan sebagaimana adanya.