使用Apache HttpClient發(fā)送HTTP請求

技術(shù)公眾號:Java In Mind(Java_In_Mind),歡迎關(guān)注哈误!

HttpComponents HttpClient 簡介

HttpClient屬于Apache HttpComponents項目,基于HttpCore,支持HTTP代理實現(xiàn)税弃,支持狀態(tài)管理,連接管理,自定義結(jié)果處理等功能,代替原先的Commons HttpClient 3.x蚓聘。

HttpClient是比較實用的Http請求客戶端,相比HttpURLConnection來說封裝性更好盟劫,也提供了許多用戶自定義以及拓展的能力夜牡,下面簡單來使用一下:

模擬服務(wù)

@RestController
@RequestMapping("/demo")
@SpringBootApplication
@Slf4j
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    private List<Foo> foos = new CopyOnWriteArrayList<>();

    @GetMapping("/list")
    public ResponseEntity list(@RequestParam(value = "name") String name) {
        log.info("accept a list request...");
        return ResponseEntity.ok(foos.stream().filter(i -> i.getName().equals(name)).collect(Collectors.toList()));
    }

    @PostMapping
    public ResponseEntity create(@RequestBody Foo foo) {
        log.info("accept create request,foo:{}", foo);
        foos.add(foo);
        return ResponseEntity.ok(foo);
    }

    @GetMapping("/error")
    public ResponseEntity error() {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("error");
    }

    @GetMapping("/redirect")
    public ResponseEntity redirect() {
        return ResponseEntity.status(HttpStatus.FOUND).header(HttpHeaders.LOCATION, "http://www.baidu.com").build();
    }


    @Data
    @AllArgsConstructor
    public static class Foo {
        private String name;
        private int age;
    }
}

發(fā)起POST請求

//request body
Map<String, String> foo = new HashMap<>();
foo.put("name", "HTTP");
foo.put("age", "18");

HttpUriRequest request = RequestBuilder.post().setUri("http://localhost:8080/demo")
    .setEntity(new StringEntity(JSONObject.toJSONString(foo), ContentType.APPLICATION_JSON)).build();

CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
//錯誤判斷
if (statusCode >= 200 & statusCode < 300) {
    String body = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8.name());
    log.info("請求結(jié)果:{}", body);
} else {
    log.error("請求錯誤,statusCode={}", statusCode);
}

發(fā)起Get請求

HttpUriRequest request = RequestBuilder.get().setUri("http://localhost:8080/demo/list")
    .addParameter("name", "HTTP").addHeader("Content-Type", "application/json").build();
        
//設(shè)置超時
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(1000 * 5).build();

CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();

CloseableHttpResponse response = httpClient.execute(request);

System.out.println(response);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode >= 200 & statusCode < 300) {
    String body = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8.name());
    log.info("請求結(jié)果:{}", body);
} else {
    log.error("請求錯誤侣签,statusCode={}", statusCode);
}

使用BasicResponseHandler處理結(jié)果

HttpUriRequest request = RequestBuilder.get().setUri("http://localhost:8080/demo/error")
    .addHeader("Content-Type", "application/json").build();
CloseableHttpClient httpClient = HttpClients.custom().build();
try {
    String response = httpClient.execute(request, new BasicResponseHandler());
    System.out.println(response);
} catch (HttpResponseException e) {
    log.error("error,code={},message={}", e.getStatusCode(), e.getMessage(), e);
}

設(shè)置超時

// 備注塘装,socketTimeout指接收數(shù)據(jù)時的超時急迂,connectTimeout指的是建立連接的超時
RequestConfig.custom()
                .setSocketTimeout(5 * 1000)//socket超時
                .setConnectTimeout(10 * 1000)//連接超時
                  .setConnectionRequestTimeout(5000)//從連接池獲取連接的超時時間
                .build();

常用配置(官方例子)

/*
 * ====================================================================
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.http.examples.client;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.CodingErrorAction;
import java.util.Arrays;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.MessageConstraints;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.ManagedHttpClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultHttpResponseParser;
import org.apache.http.impl.conn.DefaultHttpResponseParserFactory;
import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultDnsResolver;
import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
import org.apache.http.io.HttpMessageParser;
import org.apache.http.io.HttpMessageParserFactory;
import org.apache.http.io.HttpMessageWriterFactory;
import org.apache.http.io.SessionInputBuffer;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicLineParser;
import org.apache.http.message.LineParser;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EntityUtils;

/**
 * This example demonstrates how to customize and configure the most common aspects
 * of HTTP request execution and connection management.
 */
public class ClientConfiguration {

    public final static void main(String[] args) throws Exception {

        // Use custom message parser / writer to customize the way HTTP
        // messages are parsed from and written out to the data stream.
        HttpMessageParserFactory<HttpResponse> responseParserFactory = new DefaultHttpResponseParserFactory() {

            @Override
            public HttpMessageParser<HttpResponse> create(
                SessionInputBuffer buffer, MessageConstraints constraints) {
                LineParser lineParser = new BasicLineParser() {

                    @Override
                    public Header parseHeader(final CharArrayBuffer buffer) {
                        try {
                            return super.parseHeader(buffer);
                        } catch (ParseException ex) {
                            return new BasicHeader(buffer.toString(), null);
                        }
                    }

                };
                return new DefaultHttpResponseParser(
                    buffer, lineParser, DefaultHttpResponseFactory.INSTANCE, constraints) {

                    @Override
                    protected boolean reject(final CharArrayBuffer line, int count) {
                        // try to ignore all garbage preceding a status line infinitely
                        return false;
                    }

                };
            }

        };
        HttpMessageWriterFactory<HttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory();

        // Use a custom connection factory to customize the process of
        // initialization of outgoing HTTP connections. Beside standard connection
        // configuration parameters HTTP connection factory can define message
        // parser / writer routines to be employed by individual connections.
        HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
                requestWriterFactory, responseParserFactory);

        // Client HTTP connection objects when fully initialized can be bound to
        // an arbitrary network socket. The process of network socket initialization,
        // its connection to a remote address and binding to a local one is controlled
        // by a connection socket factory.

        // SSL context for secure connections can be created either based on
        // system or application specific properties.
        SSLContext sslcontext = SSLContexts.createSystemDefault();

        // Create a registry of custom connection socket factories for supported
        // protocol schemes.
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.INSTANCE)
            .register("https", new SSLConnectionSocketFactory(sslcontext))
            .build();

        // Use custom DNS resolver to override the system DNS resolution.
        DnsResolver dnsResolver = new SystemDefaultDnsResolver() {

            @Override
            public InetAddress[] resolve(final String host) throws UnknownHostException {
                if (host.equalsIgnoreCase("myhost")) {
                    return new InetAddress[] { InetAddress.getByAddress(new byte[] {127, 0, 0, 1}) };
                } else {
                    return super.resolve(host);
                }
            }

        };

        // Create a connection manager with custom configuration.
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
                socketFactoryRegistry, connFactory, dnsResolver);

        // Create socket configuration
        SocketConfig socketConfig = SocketConfig.custom()
            .setTcpNoDelay(true)
            .build();
        // Configure the connection manager to use socket configuration either
        // by default or for a specific host.
        connManager.setDefaultSocketConfig(socketConfig);
        connManager.setSocketConfig(new HttpHost("somehost", 80), socketConfig);
        // Validate connections after 1 sec of inactivity
        connManager.setValidateAfterInactivity(1000);

        // Create message constraints
        MessageConstraints messageConstraints = MessageConstraints.custom()
            .setMaxHeaderCount(200)
            .setMaxLineLength(2000)
            .build();
        // Create connection configuration
        ConnectionConfig connectionConfig = ConnectionConfig.custom()
            .setMalformedInputAction(CodingErrorAction.IGNORE)
            .setUnmappableInputAction(CodingErrorAction.IGNORE)
            .setCharset(Consts.UTF_8)
            .setMessageConstraints(messageConstraints)
            .build();
        // Configure the connection manager to use connection configuration either
        // by default or for a specific host.
        connManager.setDefaultConnectionConfig(connectionConfig);
        connManager.setConnectionConfig(new HttpHost("somehost", 80), ConnectionConfig.DEFAULT);

        // Configure total max or per route limits for persistent connections
        // that can be kept in the pool or leased by the connection manager.
        connManager.setMaxTotal(100);
        connManager.setDefaultMaxPerRoute(10);
        connManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 20);

        // Use custom cookie store if necessary.
        CookieStore cookieStore = new BasicCookieStore();
        // Use custom credentials provider if necessary.
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        // Create global request configuration
        RequestConfig defaultRequestConfig = RequestConfig.custom()
            .setCookieSpec(CookieSpecs.DEFAULT)
            .setExpectContinueEnabled(true)
            .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
            .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
            .build();

        // Create an HttpClient with the given custom dependencies and configuration.
        CloseableHttpClient httpclient = HttpClients.custom()
            .setConnectionManager(connManager)
            .setDefaultCookieStore(cookieStore)
            .setDefaultCredentialsProvider(credentialsProvider)
            .setProxy(new HttpHost("myproxy", 8080))
            .setDefaultRequestConfig(defaultRequestConfig)
            .build();

        try {
            HttpGet httpget = new HttpGet("http://httpbin.org/get");
            // Request configuration can be overridden at the request level.
            // They will take precedence over the one set at the client level.
            RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
                .setSocketTimeout(5000)
                .setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000)
                .setProxy(new HttpHost("myotherproxy", 8080))
                .build();
            httpget.setConfig(requestConfig);

            // Execution context can be customized locally.
            HttpClientContext context = HttpClientContext.create();
            // Contextual attributes set the local context level will take
            // precedence over those set at the client level.
            context.setCookieStore(cookieStore);
            context.setCredentialsProvider(credentialsProvider);

            System.out.println("executing request " + httpget.getURI());
            CloseableHttpResponse response = httpclient.execute(httpget, context);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                System.out.println(EntityUtils.toString(response.getEntity()));
                System.out.println("----------------------------------------");

                // Once the request has been executed the local context can
                // be used to examine updated state and various objects affected
                // by the request execution.

                // Last executed request
                context.getRequest();
                // Execution route
                context.getHttpRoute();
                // Target auth state
                context.getTargetAuthState();
                // Proxy auth state
                context.getProxyAuthState();
                // Cookie origin
                context.getCookieOrigin();
                // Cookie spec used
                context.getCookieSpec();
                // User security token
                context.getUserToken();

            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}

總結(jié)

HttpClient是我們常用的Http客戶端,了解熟悉API以及相關(guān)配置有利于我們更好的使用蹦肴,一般場景下使用默認(rèn)的配置都能滿足要求袋毙,如果有特殊的要求也支持自定義配置。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冗尤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子胀溺,更是在濱河造成了極大的恐慌裂七,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仓坞,死亡現(xiàn)場離奇詭異背零,居然都是意外死亡,警方通過查閱死者的電腦和手機无埃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門徙瓶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嫉称,你說我怎么就攤上這事侦镇。” “怎么了织阅?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵壳繁,是天一觀的道長。 經(jīng)常有香客問我荔棉,道長闹炉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任润樱,我火速辦了婚禮渣触,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘壹若。我一直安慰自己嗅钻,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布舌稀。 她就那樣靜靜地躺著啊犬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪壁查。 梳的紋絲不亂的頭發(fā)上觉至,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音睡腿,去河邊找鬼语御。 笑死峻贮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的应闯。 我是一名探鬼主播纤控,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碉纺!你這毒婦竟也來了船万?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤骨田,失蹤者是張志新(化名)和其女友劉穎耿导,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體态贤,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡舱呻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了悠汽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箱吕。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖柿冲,靈堂內(nèi)的尸體忽然破棺而出茬高,到底是詐尸還是另有隱情,我是刑警寧澤假抄,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布雅采,位于F島的核電站,受9級特大地震影響慨亲,放射性物質(zhì)發(fā)生泄漏婚瓜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一刑棵、第九天 我趴在偏房一處隱蔽的房頂上張望巴刻。 院中可真熱鬧,春花似錦蛉签、人聲如沸胡陪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柠座。三九已至,卻和暖如春片橡,著一層夾襖步出監(jiān)牢的瞬間妈经,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吹泡,地道東北人骤星。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像爆哑,于是被迫代替她去往敵國和親洞难。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容