HttpClient 发送 http 请求

简单介绍

HTTP 的全称是Hypertext Transfer Protocol Vertion (超文本传输协议),就是用网络链接传输文本信息的协议,是现在互联网中广泛使用的协议。
除了 HTTP 协议,还有 HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer)协议,它是在 HTTP 下加入SSL层,以用来进行安全的 HTTP 数据传输,可以说是 HTTP 的安全版。
这里使用 JAVA 语言,参照Apache HttpClient的官网,总结了 HttpClient 的一些关于 HTTP 请求的使用,方便以后使用。

使用

HTTP 请求

发起 HTTP 请求首先要有请求的 URI :

  • 可以直接使用 HttpGet 的构造方法:
HttpGet httpget = new HttpGet("http://www.google.com/search?hl=en&&btnG=Google+Search&aq=f&oq=");
  • 也可以使用HttpClient提供URIBuilder:
URI uri = new URIBuilder()
        .setScheme("http")
        .setHost("www.google.com")
        .setPath("/search")
        .setParameter("btnG", "Google Search")
        .setParameter("aq", "f")
        .setParameter("oq", "")
        .build();
HttpGet httpget = new HttpGet(uri);
// 打印URL最后的完整名称
System.out.println(httpget.getURI());
//显示结果:http://www.google.com/search?&btnG=Google+Search&aq=f&oq=

有了 URI 就可以发起简单的 HTTP 请求了:

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse  response = httpclient.execute(target,request);
System.out.println("网络请求: "+response1.toString());
//发起一次网络请求就会建立一次网络连接这很占资源,所以最后在不用时最后释放掉
esponse.close();
httpclient.close();

在成功接收请求消息之后服务器会发送回客户端的消息-HttpResponse ,该消息的第一行中包括协议版本,数字状态代码及其关联的文本短语:

//构建一个返回数据
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 
HttpStatus.SC_OK, "OK");
//协议版本
System.out.println(response.getProtocolVersion());
//返回的状态码
System.out.println(response.getStatusLine().getStatusCode());
//返回状态码关联文本
System.out.println(response.getStatusLine().getReasonPhrase());
//服务器返回的数据中第一行完整字符串
System.out.println(response.getStatusLine().toString());

返回结果如下:

HTTP/1.1
200
OK
HTTP/1.1 200 OK

对于服务端返回的数据中有描述消息属性的多个头部,如内容长度,内容类型等。HttpClient也提供了对这些内容的检索,添加,删除和枚举头文件的方法。

//构建一个返回数据
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,HttpStatus.SC_OK, "OK");
response.addHeader("Set-Cookie","c1=a; path=/; domain=localhost");
response.addHeader("Set-Cookie","c2=b; path=\"/\", c3=c; domain=\"localhost\"");
//过去消息头数据
Header h1 = response.getFirstHeader("Set-Cookie");
System.out.println(h1);
Header h2 = response.getLastHeader("Set-Cookie");
System.out.println(h2);
Header[] hs = response.getHeaders("Set-Cookie");
System.out.println(hs.length);

当然,HttpResponse 还提供了 HeaderIterator 方法用来遍历所有标头:

HeaderIterator it = response.headerIterator("Set-Cookie");
while (it.hasNext()) {
    System.out.println(it.next());
}

接下来就是获取服务器返回的数据的主要文本信息了,HttpEntity
entity就是发送或者接收消息的载体,entity可以从 request 和 response 中获取:

HttpEntity entity = response.getEntity();
//打印返回的状态
System.out.println(response.getStatusLine());
      if (entity != null) {
//打印返回的内容长度
System.out.println("Response content length: " + entity.getContentLength());
//打印返回的数据内容
System.out.println("Response content: " + EntityUtils.toString(entity));
            }
使用代理发起 HTTP 请求

即使HttpClient知道复杂的路由方案和代理链接,它只支持简单的直接或一跳代理连接开箱即用。
告诉HttpClient通过代理连接到目标主机的最简单方法是设置默认代理参数:

// "127.0.0.1", 8087 为代理的host 和 port 
HttpHost proxy = new HttpHost("127.0.0.1", 8087);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
        .setRoutePlanner(routePlanner)
        .build();

还可以指示 HttpClient 使用标准的JRE代理选择器来获取代理信息:

SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(
        ProxySelector.getDefault());
CloseableHttpClient httpclient = HttpClients.custom()
        .setRoutePlanner(routePlanner)
        .build();

或者,可以提供自定义RoutePlanner 实现,以便完全控制HTTP路由计算的过程:

HttpRoutePlanner routePlanner = new HttpRoutePlanner() {

    public HttpRoute determineRoute(
            HttpHost target,
            HttpRequest request,
            HttpContext context) throws HttpException {
        // "127.0.0.1", 8087 为代理的host 和 port 
        return new HttpRoute(target, null,  new HttpHost("127.0.0.1", 8087),
                "https".equalsIgnoreCase(target.getSchemeName()));
    }

};
CloseableHttpClient httpclient = HttpClients.custom()
        .setRoutePlanner(routePlanner)
        .build();
    }
}
发起 HTTPS 请求

想要发起SSL请求,需要创建 SSL 连接

/** 
* 创建 SSL连接 
* @return 
* @throws GeneralSecurityException 
*/ 
private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException { 
try { 
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, 
new TrustStrategy() { 
        public boolean isTrusted(X509Certificate[] chain, 
                String authType) throws CertificateException { 
                return true; 
} 
}).build();

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, 
new HostnameVerifier() { 
@Override 
public boolean verify(String hostname, SSLSession session) { 
return true; 
} 
});

return HttpClients.custom().setSSLSocketFactory(sslsf).build();

} catch (GeneralSecurityException e) { 
throw e; 
} 
}

设置好 SSL 连接就可以发起 HTTPS 请求了:

CloseableHttpClient httpclient = createSSLInsecureClient();
        HttpGet httpget = new HttpGet("https://www.baidu.com/");

        System.out.println("Executing request " + httpget.getRequestLine());

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            System.out.println(response.toString());
            System.out.println("entity:");
            System.out.println(EntityUtils.toString(entity, "utf-8"));
            // 确保实体内容被完全消费,并且内容流(如果存在)被关闭。
            EntityUtils.consume(entity);
        } finally {
            response.close();
            httpclient.close();
        }
    }

最后一个就是使用代理发起 HTTPS 请求:
(我试过不使用SSL连接创建CloseableHttpClient (使用 HttpClients.createDefault()方式),使用这样方式的代理,但是会报错:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 原因可以查看文章 unable to find valid certification path to requested target):

public static void httpsUseProxy() {
        CloseableHttpClient httpclient = null;
        try {
            CloseableHttpClient httpclient = createSSLInsecureClient();
            HttpHost target = new HttpHost("www.google.com", 443, "https");
                        // "127.0.0.1", 8087 为代理的host 和 port 
            HttpHost proxy = new HttpHost("127.0.0.1", 8087, "http");
            RequestConfig config = RequestConfig.custom().setProxy(proxy)
                    // HTTP连接超时时间
                    .setConnectTimeout(5000)
                    // HTTP请求超时时间
                    .setConnectionRequestTimeout(5000)
                    // HTTP套接字SOCKET超时时间
                    .setSocketTimeout(5000).build();
            HttpGet request = new HttpGet("/");
            request.setConfig(config);

            System.out.println("Executing request " + request.getRequestLine() + " to " + target + " via " + proxy);
            CloseableHttpResponse response = httpclient.execute(target, request);
                System.out.println("--服务端返回的数据状态信息-------");
                System.out.println(response.getStatusLine());
                System.out.println(EntityUtils.toString(response.getEntity()));
                response.close();
                
        } catch(IOException e){
        } catch (GeneralSecurityException e) {
        }finally {
                        httpclient.close();
        }
    }

总结

之前项目需要,要使用 JAVA 发起HTTP 和 HTTPS 请求。由于公司要使用代理才可以上网,所以在网上看Apache 的 HttpClient 官方文档才有了这文章。
这里只是总结了一下 HttpClient 的 HTTP , HTTPS 请求以及使用代理的简单使用,通过官方文档,发现 HttpClient 还有很多很多的用法,以后有需要时在总结吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容