HttpClient基础解析

网友投稿 315 2023-04-04


HttpClient基础解析

本文讲述了HttpClient基础知识,对相关概念进行解释在这里分享给大家,供大家参考。

1. 请求执行:

HttpClient最重要的功能是执行HTTP方法。执行HTTP方法涉及一个或多个HTTP请求/ HTTP响应交换,通常由HttpClient内部处理。用户期望提供一个请求对象来执行,并且希望HttpClient将请求发送到目标服务器返回相应的响应对象,如果执行失败则抛出异常。

很自然,HttpClient API的主要入口点是定义上述合同的HttpClient接口。

这是一个请求执行过程的一个例子,它的最简单的形式是:

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("https://localhost/");

CloseableHttpResponse response = httpclient.execute(httpget);

try {

<...>

} finally {

response.close();

}

1.1. HTTP请求

所有HTTP请求都有一个请求行,包括方法名称,请求URI和HTTP协议版本。

HttpClient的支持了在HTTP / 1.1规范中定义的所有HTTP方法的框的:GET,HEAD, POST,PUT,DELETE, TRACE和OPTIONS。没有为每个方法类型:一个特定的类HttpGet, HttpHead,HttpPost, HttpPut,HttpDelete, HttpTrace,和HttpOptions。

Request-URI是统一资源标识符,用于标识应用请求的资源。HTTP请求URI由协议方案,主机名,可选端口,资源路径,可选查询和可选片段组成。

URI uri = new URIBuilder()

.setScheme("http")

.setHost("google.com")

.setPath("/search")

.setParameter("q", "httpclient")

.setParameter("btnG", "Google Search")

.setParameter("aq", "f")

.setParameter("oq", "")

.build();

HttpGet httpget = new HttpGet(uri);

System.out.println(httpget.getURI());

1.2. HTTP响应

HTTP响应是在接收和解释请求消息之后由服务器发送回客户端的消息。该消息的第一行包括协议版本,后跟数字状态代码及其关联的文本短语。

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

*/

1.3. 处理消息头

HTTP消息可以包含描述消息属性的多个头部,如内容长度,内容类型等。HttpClient提供了检索,添加,删除和枚举头文件的方法。

获取给定类型的所有标头的最有效的方法是使用 HeaderIterator接口。

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 \"");

HeaderIterator it = response.headerIterator("Set-Cookie");

while(it.hasNext()){

System.out.println(it.next());

}

它还提供了方便的方法来将HTTP消息解析为单独的头元素。

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 \"");

HeaderElementIterator it = new BasicHeaderElementIterator(

response.headerIterator("Set-Cookie"));

while(it.hasNext()){

HeaderElement elem = it.nextElement();

System.out.println(elem.getName()+"="+ elem.getValue());

NameValuePair [] params = elem.getParameters();

for(int i = 0; i

System.out。println(""+ params [i]);

}

}

1.4. HTTP实体

HTTP消息可以携带与请求或响应相关联的内容实体。实体可以在一些请求和一些响应中找到,因为它们是可选的。使用实体的请求被称为实体封装请求。HTTP规范定义了两个实体封装请求方法:POST和 PUT。响应通常期望包含内容实体。有例外的情况,如应对 HEAD方法204 No Content, 304 Not Modified,205 Reset Content 响应。

HttpClient根据其内容来源区分三种实体:

streamed: 内容是从流中接收的,或者即时生成的。特别地,该类别包括从HTTP响应接收到的实体。流式实体通常不可重复。

self-contained: 内容在内存中或通过独立于连接或其他实体的方式获取。自包含的实体通常是可重复的。这种类型的实体将主要用于封闭HTTP请求的实体。

wrapping: 内容是从另一个实体获得的。

当从HTTP响应流出内容时,此区别对于连接管理很重要。对于由应用程序创建并且仅使用HttpClient发送的请求实体,流和独立的区别不重要。在这种情况下,建议将不可重复的实体视为流式传输,将可重复的实体视为独立的。

1.4.1. 可重复的实体

实体可以是可重复的,这意味着它的内容可以被读取不止一次。这是唯一可能的自包含的实体(像 ByteArrayEntity或 StringEntity)

1.4.2. 使用HTTP实体

由于实体可以表示二进制和字符内容,它支持字符编码(以支持后者,即字符内容)。

当执行带有封闭内容的请求时,或者当请求成功并且使用响应主体将结果发送回客户端时,实体被创建。

要从实体读取内容,可以通过HttpEntity.getContent()方法来检索输入流,该方法返回一个java.io.InputStream,或者可以向HttpEntity.writeTo(OutputStream)方法提供输出流,一旦所有内容已写入给定流,该方法将返回。

当实体已经接收到传入消息时,方法 HttpEntity.getContentType()和 HttpEntity.getContentLength()方法可用于读取公共元数据,如头Content-Type和 Content-Length头(如果可用)。由于 Content-Type标题可以包含text / plain或text / html等文本MIME类型的字符编码,因此该 HttpEntity.getContentEncoding()方法用于读取此信息。如果标题不可用,则返回长度为-1,内容类型为NULL。如果Content-Type 标题可用,Header将返回一个对象。

当为外发消息创建实体时,该元数据必须由实体的创建者提供。

StringEntity myEntity = new StringEntity("important message",

ContentType.create("text/plain", "UTF-8"));

System.out.println(myEntity.getContentType());

System.out.println(myEntity.getContentLength());

System.out.println(EntityUtils.toString(myEntity));

System.out.println(EntityUtils.toByteArray(myEntity).length);

1.5. 确保发布低级别资源

为了确保系统资源的正确释放,必须关闭与实体或响应本身相关联的内容流

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http:// localhost /");

CloseableHttpResponse response = httpclient.execute(httpget);

try{

HttpEntity entity = response.getEntity();

if(entity!= null){

InputStream instream = entity.getContent();

try{

//做一些有用的事情

} finally {

instream.close();

}

}

} finally {

response.close();

}

关闭内容流和关闭响应之间的区别在于,前者将尝试通过占用实体内容来保持底层连接,而后者会立即关闭并放弃连接。

请注意,HttpEntity.writeTo(OutputStream) 一旦实体完全写出,还需要确保正确释放系统资源的方法。如果此方法获取一个java.io.InputStream通过调用 的实例 HttpEntity.getContent(),那么也希望在finally子句中关闭流。

当使用流实体时,可以使用该 EntityUtils.consume(HttpEntity)方法来确保实体内容已被完全消耗,底层流已经被关闭。

然而,可能会有情况,当只需要检索整个响应内容的一小部分时,消耗剩余内容并使连接可重用的性能损失太高,在这种情况下,可以通过关闭终止内容流响应。

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http:// localhost /");

CloseableHttpResponse response = httpclient.execute(httpget);

try{

HttpEntity entity = response.getEntity();

if(entity!= null){

InputStream instream = entity.getContent();

int byteOne = instream.read();

int byteTwo = instream.read();

//不需要休息

}

} finally {

response.close();

}

连接不会重复使用,但由其持有的所有级别资源将被正确地分配。

1.6. 消费实体内容

消费实体内容的推荐方法是使用它 HttpEntity.getContent()或 HttpEntity.writeTo(OutputStream)方法。HttpClient还附带了EntityUtils类,它暴露了几种静态方法,以便更容易地从实体读取内容或信息。java.io.InputStream可以使用这个类的方法,而不是直接读取,而不是直接读取字符串/字节数组中的整个内容正文。但是,EntityUtils除非响应实体来自可信HTTP服务器,而且已知其长度有限,否则强烈建议不要使用此功能。

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http:// localhost /");

CloseableHttpResponse response = httpclient.execute(httpget);

try{

HttpEntity entity = response.getEntity();

if(entity!= null){

long len = entity.getContentLength();

if(len!= -1 && len <2048){

System.out.println(EntityUtils.toString(entity));

} else {

// Stream content out

}

}

} finally {

response.close();

}

在某些情况下,可能需要多次读取实体内容。在这种情况下,实体内容必须以某种方式缓存,无论是在内存还是在磁盘上。最简单的方法是通过用BufferedHttpEntity类包装原始实体。这将导致将原始实体的内容读入内存缓冲区。在所有其他方面,实体包装器将具有原始包装器。

CloseableHttpResponse respoXFIfyeDHqTnse = <...>

HttpEntity entity = response.getEntity();

if(entity!= null){

entity = new BufferedHttpEntity(entity);

}

1.7. 制作实体内容

HttpClient提供了几个类,可以通过HTTP连接高效地流出内容。这些类的实例可以与实体包围请求,如相关联POST并PUT 以包围实体内容分成传出HTTP请求。HttpClient的提供了几个类为最常见的数据的容器,如字符串,字节数组,输入流,和文件:StringEntity, ByteArrayEntity, InputStreamEntity,和 FileEntity。

File file = new File("somefile.txt");

FileEntity entity = new FileEntity(file,

ContentType.create("text / plain","UTF-8"));

HttpPost httppost = new HttpPost("http://localhost/action.do");

httppost.setEntity(entity);

1.7.1 HTML表单

许多应用程序需要模拟提交HTML表单的过程,例如,以登录到Web应用程序或提交输入数据。HttpClient提供实体类 UrlEncodedFormEntity来促进进程。

List formparams = new ArrayList ();

formparams.add(new BasicNameValuePair("param1","value1"));

formparams.add(new BasicNameValuePair("param2","value2"));

UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,Consts.UTF_8);

HttpPost httppost = new HttpPost("http://localhost/handler.do");

httppost.setEntity(entity);

该UrlEncodedFormEntity实例将使用所谓的URL编码来对参数进行编码并产生以下内容:

param1=value1&param2=value2

1.7.2. 内容分块

一般建议让HttpClient根据正在传输的HTTP消息的属性选择最合适的传输编码。然而,可以通知HttpClient,通过设置HttpEntity.setChunked()为true,优先选择块编码。请注意,HttpClient只会使用此标志作为提示。当使用不支持块编码的HTTP协议版本(如HTTP / 1.0)时,此值将被忽略。

StringEntity entity = new StringEntity("important message",

ContentType.create("plain / text",Consts.UTF_8));

entity.setChunked(true);

HttpPost httppost = new HttpPost("http://localhost/acrtion.do");

httppost.setEntity(entity);

1.8. 响应处理程序

处理响应的最简单和最方便的方法是使用ResponseHandler包含该handleResponse(HttpResponse response)方法的界面。这种方法完全可以缓解用户不必担心连接管理。使用ResponseHandlerHttpClient 时 ,无论请求执行是成功还是导致异常,HttpClient都会自动保证将连接释放回连接管理器。

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http://localhost/json");

ResponseHandler rh = new ResponseHandler() {

@Override

public JsonObject handleResponse(

final HttpResponse response) throws IOException {

StatusLine statusLine = response.getStatusLine();

HttpEntity entity = response.getEntity();

if (statusLine.getStatusCode() >= 300) {

throw new HttpResponseException(

statusLine.getStatusCode(),

statusLine.getReasonPhrase());

}

if (entity == null) {

throw new ClientProtocolException("Response contains no content");

}

Gson gson = new GsonBuilder().create();

ContentType contentType = ContentType.getOrDefault(entity);

Charset charset = contentType.getCharset();

Reader reader = new InputStreamReader(entity.getContent(), charset);

return gson.fromJson(reader, MyJsonObject.class);

}

};

MyJsonObject myjson = client.execute(httpget, rh);

总结

以上是本文对HttpClient基础知识的全部介绍,希望对大家有所帮助。

System.out。println(""+ params [i]);

}

}

1.4. HTTP实体

HTTP消息可以携带与请求或响应相关联的内容实体。实体可以在一些请求和一些响应中找到,因为它们是可选的。使用实体的请求被称为实体封装请求。HTTP规范定义了两个实体封装请求方法:POST和 PUT。响应通常期望包含内容实体。有例外的情况,如应对 HEAD方法204 No Content, 304 Not Modified,205 Reset Content 响应。

HttpClient根据其内容来源区分三种实体:

streamed: 内容是从流中接收的,或者即时生成的。特别地,该类别包括从HTTP响应接收到的实体。流式实体通常不可重复。

self-contained: 内容在内存中或通过独立于连接或其他实体的方式获取。自包含的实体通常是可重复的。这种类型的实体将主要用于封闭HTTP请求的实体。

wrapping: 内容是从另一个实体获得的。

当从HTTP响应流出内容时,此区别对于连接管理很重要。对于由应用程序创建并且仅使用HttpClient发送的请求实体,流和独立的区别不重要。在这种情况下,建议将不可重复的实体视为流式传输,将可重复的实体视为独立的。

1.4.1. 可重复的实体

实体可以是可重复的,这意味着它的内容可以被读取不止一次。这是唯一可能的自包含的实体(像 ByteArrayEntity或 StringEntity)

1.4.2. 使用HTTP实体

由于实体可以表示二进制和字符内容,它支持字符编码(以支持后者,即字符内容)。

当执行带有封闭内容的请求时,或者当请求成功并且使用响应主体将结果发送回客户端时,实体被创建。

要从实体读取内容,可以通过HttpEntity.getContent()方法来检索输入流,该方法返回一个java.io.InputStream,或者可以向HttpEntity.writeTo(OutputStream)方法提供输出流,一旦所有内容已写入给定流,该方法将返回。

当实体已经接收到传入消息时,方法 HttpEntity.getContentType()和 HttpEntity.getContentLength()方法可用于读取公共元数据,如头Content-Type和 Content-Length头(如果可用)。由于 Content-Type标题可以包含text / plain或text / html等文本MIME类型的字符编码,因此该 HttpEntity.getContentEncoding()方法用于读取此信息。如果标题不可用,则返回长度为-1,内容类型为NULL。如果Content-Type 标题可用,Header将返回一个对象。

当为外发消息创建实体时,该元数据必须由实体的创建者提供。

StringEntity myEntity = new StringEntity("important message",

ContentType.create("text/plain", "UTF-8"));

System.out.println(myEntity.getContentType());

System.out.println(myEntity.getContentLength());

System.out.println(EntityUtils.toString(myEntity));

System.out.println(EntityUtils.toByteArray(myEntity).length);

1.5. 确保发布低级别资源

为了确保系统资源的正确释放,必须关闭与实体或响应本身相关联的内容流

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http:// localhost /");

CloseableHttpResponse response = httpclient.execute(httpget);

try{

HttpEntity entity = response.getEntity();

if(entity!= null){

InputStream instream = entity.getContent();

try{

//做一些有用的事情

} finally {

instream.close();

}

}

} finally {

response.close();

}

关闭内容流和关闭响应之间的区别在于,前者将尝试通过占用实体内容来保持底层连接,而后者会立即关闭并放弃连接。

请注意,HttpEntity.writeTo(OutputStream) 一旦实体完全写出,还需要确保正确释放系统资源的方法。如果此方法获取一个java.io.InputStream通过调用 的实例 HttpEntity.getContent(),那么也希望在finally子句中关闭流。

当使用流实体时,可以使用该 EntityUtils.consume(HttpEntity)方法来确保实体内容已被完全消耗,底层流已经被关闭。

然而,可能会有情况,当只需要检索整个响应内容的一小部分时,消耗剩余内容并使连接可重用的性能损失太高,在这种情况下,可以通过关闭终止内容流响应。

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http:// localhost /");

CloseableHttpResponse response = httpclient.execute(httpget);

try{

HttpEntity entity = response.getEntity();

if(entity!= null){

InputStream instream = entity.getContent();

int byteOne = instream.read();

int byteTwo = instream.read();

//不需要休息

}

} finally {

response.close();

}

连接不会重复使用,但由其持有的所有级别资源将被正确地分配。

1.6. 消费实体内容

消费实体内容的推荐方法是使用它 HttpEntity.getContent()或 HttpEntity.writeTo(OutputStream)方法。HttpClient还附带了EntityUtils类,它暴露了几种静态方法,以便更容易地从实体读取内容或信息。java.io.InputStream可以使用这个类的方法,而不是直接读取,而不是直接读取字符串/字节数组中的整个内容正文。但是,EntityUtils除非响应实体来自可信HTTP服务器,而且已知其长度有限,否则强烈建议不要使用此功能。

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http:// localhost /");

CloseableHttpResponse response = httpclient.execute(httpget);

try{

HttpEntity entity = response.getEntity();

if(entity!= null){

long len = entity.getContentLength();

if(len!= -1 && len <2048){

System.out.println(EntityUtils.toString(entity));

} else {

// Stream content out

}

}

} finally {

response.close();

}

在某些情况下,可能需要多次读取实体内容。在这种情况下,实体内容必须以某种方式缓存,无论是在内存还是在磁盘上。最简单的方法是通过用BufferedHttpEntity类包装原始实体。这将导致将原始实体的内容读入内存缓冲区。在所有其他方面,实体包装器将具有原始包装器。

CloseableHttpResponse respoXFIfyeDHqTnse = <...>

HttpEntity entity = response.getEntity();

if(entity!= null){

entity = new BufferedHttpEntity(entity);

}

1.7. 制作实体内容

HttpClient提供了几个类,可以通过HTTP连接高效地流出内容。这些类的实例可以与实体包围请求,如相关联POST并PUT 以包围实体内容分成传出HTTP请求。HttpClient的提供了几个类为最常见的数据的容器,如字符串,字节数组,输入流,和文件:StringEntity, ByteArrayEntity, InputStreamEntity,和 FileEntity。

File file = new File("somefile.txt");

FileEntity entity = new FileEntity(file,

ContentType.create("text / plain","UTF-8"));

HttpPost httppost = new HttpPost("http://localhost/action.do");

httppost.setEntity(entity);

1.7.1 HTML表单

许多应用程序需要模拟提交HTML表单的过程,例如,以登录到Web应用程序或提交输入数据。HttpClient提供实体类 UrlEncodedFormEntity来促进进程。

List formparams = new ArrayList ();

formparams.add(new BasicNameValuePair("param1","value1"));

formparams.add(new BasicNameValuePair("param2","value2"));

UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,Consts.UTF_8);

HttpPost httppost = new HttpPost("http://localhost/handler.do");

httppost.setEntity(entity);

该UrlEncodedFormEntity实例将使用所谓的URL编码来对参数进行编码并产生以下内容:

param1=value1&param2=value2

1.7.2. 内容分块

一般建议让HttpClient根据正在传输的HTTP消息的属性选择最合适的传输编码。然而,可以通知HttpClient,通过设置HttpEntity.setChunked()为true,优先选择块编码。请注意,HttpClient只会使用此标志作为提示。当使用不支持块编码的HTTP协议版本(如HTTP / 1.0)时,此值将被忽略。

StringEntity entity = new StringEntity("important message",

ContentType.create("plain / text",Consts.UTF_8));

entity.setChunked(true);

HttpPost httppost = new HttpPost("http://localhost/acrtion.do");

httppost.setEntity(entity);

1.8. 响应处理程序

处理响应的最简单和最方便的方法是使用ResponseHandler包含该handleResponse(HttpResponse response)方法的界面。这种方法完全可以缓解用户不必担心连接管理。使用ResponseHandlerHttpClient 时 ,无论请求执行是成功还是导致异常,HttpClient都会自动保证将连接释放回连接管理器。

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpGet httpget = new HttpGet("http://localhost/json");

ResponseHandler rh = new ResponseHandler() {

@Override

public JsonObject handleResponse(

final HttpResponse response) throws IOException {

StatusLine statusLine = response.getStatusLine();

HttpEntity entity = response.getEntity();

if (statusLine.getStatusCode() >= 300) {

throw new HttpResponseException(

statusLine.getStatusCode(),

statusLine.getReasonPhrase());

}

if (entity == null) {

throw new ClientProtocolException("Response contains no content");

}

Gson gson = new GsonBuilder().create();

ContentType contentType = ContentType.getOrDefault(entity);

Charset charset = contentType.getCharset();

Reader reader = new InputStreamReader(entity.getContent(), charset);

return gson.fromJson(reader, MyJsonObject.class);

}

};

MyJsonObject myjson = client.execute(httpget, rh);

总结

以上是本文对HttpClient基础知识的全部介绍,希望对大家有所帮助。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Maven优雅的添加第三方Jar包的方法
下一篇:java线性表的存储结构及其代码实现
相关文章

 发表评论

暂时没有评论,来抢沙发吧~