欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

HttpClient基础解析

程序员文章站 2024-02-29 16:05:46
本文讲述了httpclient基础知识,对相关概念进行解释在这里分享给大家,供大家参考。 1. 请求执行: httpclient最重要的功能是执行http方法。执行...

本文讲述了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("www.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 <params.length; 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 response = <...> 
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 <namevaluepair> formparams = new arraylist <namevaluepair>(); 
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<myjsonobject> rh = new responsehandler<myjsonobject>() {
 @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基础知识的全部介绍,希望对大家有所帮助。