- 浏览: 152304 次
- 性别:
- 来自: 北京
最新评论
-
huzhiyong56:
如果把它放在weblogic服务器上?图片还取得到吗?
jquery插件:图片上传按比例预览 -
daly1987:
好文章啊。。。
Eclipse调试tomcat时报45秒超时 -
zfting:
哥哥!!连IE都不支持!!我的个晕!
jquery插件:图片上传按比例预览 -
seyaa:
谢谢分享 解决了 我的问题
jquery插件:图片上传按比例预览
1.1 执行请求
HttpClient的最重要的功能是执行HTTP方法。一个HTTP方法的执行涉及到一个或多个HTTP请求或HTTP响应的交流,HttpClient通常是在内部处理的。用户将提供一个执行请求对象,HttpClient发送请求到目标服务器返回一个相应的响应对象,如果执行失败则抛出一个异常。所以,HttpClient API的主要切入点是HttpClient的接口,它定义了上述约定。
下面是一个请求执行过程中的最简单形式的例子:
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int l;
byte[] tmp = new byte[2048];
while ((l = instream.read(tmp)) != -1) {
}
}
1.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。所有的这些类均实现了HttpUriRequest接口,故可以作为execute的执行参数使用。请求URI是能够应用请求的统一资源标识符。 HTTP请求的URI包含一个协议计划protocol scheme,主机名host name,,可选的端口optional port,资源的路径resource path,可选的查询optional query和可选的片段optional fragment。
HttpGet httpget = new HttpGet(
"http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");
HttpClient提供了一系列实用的方法来简化创建和修改请求URI。
URI可以组装编程:
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
"q=httpclient&btnG=Google+Search&aq=f&oq=", null);
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
输出>
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
查询字符串也可以通过添加参数列表来生成:
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("q", "httpclient"));
qparams.add(new BasicNameValuePair("btnG", "Google Search"));
qparams.add(new BasicNameValuePair("aq", "f"));
qparams.add(new BasicNameValuePair("oq", null));
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
URLEncodedUtils.format(qparams, "UTF-8"), null);
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
输出>
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
1.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.1.3 Headers处理
一个HTTP消息可以包含一系列headers参数描述信息,例如内容长度,内容类型等。 HttpClient的提供方法来检索,添加,删除和枚举headers。
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);
输出>
Set-Cookie: c1=a; path=/; domain=localhost
Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
2
最有效获取所有的给定类型的headers方式是使用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());
}
输出>
Set-Cookie: c1=a; path=/; domain=localhost
Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
它还提供了方便的方法来解析HTTP消息的单个header元素
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]);
}
输出>
c1 = a
path=/
domain=localhost
c2 = b
path=/
c3 = c
domain=localhost
1.1.4 HTTP 实体
HTTP消息的可以进行内容实体和请求或响应关联。可以在一些要求和一些回应中找到实体,因为它们是可选的。实体内附与请求之中。 HTTP规范定义了两个实体内附方法:POST和PUT。响应通常将会附上一个内容实体。但是响应HEAD方法和 204 No Content, 304 Not Modified, 205 Reset Content responses 除外。
HttpClient的区分三种不同实体的地方在于内容来源于:
streamed流媒体:内容是从收到的流,或在运行中产生的。特别是包括被从HTTP响应收到的实体。流媒体的实体一般不可重复。
self-contained独立的:内容是在内存或以从一个连接或其他实体的独立获得的。独立的的实体,一般可重复的。这种类型的实体将主要用于内附在HTTP请求中。
wrapping包装:实体内容是从另一个实体获得。
当得到一个HTTP响应流的内容的时候,这种区分对于连接管理是很重要的。对于请求实体,通过应用程序来创建和只通过使用的HttpClient发送,流和自载之间差别很小。在这种情况下,建议考虑非重复的流实体,以及那些重复的自载实体。
1.1.4.1 重复实体
一个实体可以是可重复的,这意味着它的内容可以被读取一次以上。唯一有可能是的独立的实体(如ByteArrayEntity或StringEntity())
1.1.4.2 使用HTTP实体
由于一个实体能够表示二进制和字符的内容,它可以提供编码的支持(支持文字、IE和字符内容)。
这个实体在执行封闭内容的请求的时候或者在请求成功和响应返回成功的时候被创建。
若要读取从实体内容,一可以通过检索HttpEntity#getContent()方法,它返回一个java.io.InputStream,或一个可以提供一个输出流的HttpEntity#writeTo(OutputStream中)方法的输入流,这将返回已被写入给定的流的所有内容。
当通过传入的消息收到实体,方法HttpEntity#getContentType()和HttpEntity#getContentLength()方法可用于阅读通用元数据metadata,如Content-Type,Content-Length headers(如果可用)。由于Content-Type header可以包含一个像text/plain或者text/html的文本mime-types的character encoding,HttpEntity#getContentEncoding()方法用来读取此信息。如果headers是不可用,返回的长度是-1,content type并为NUL。如果Content – Type header可用,将返回一个header对象。
当创建了一个即将卸任的消息实体,该meta data必须提供由该实体的创造者。
StringEntity myEntity = new StringEntity("important message",
"UTF-8");
System.out.println(myEntity.getContentType());
System.out.println(myEntity.getContentLength());
System.out.println(EntityUtils.getContentCharSet(myEntity));
System.out.println(EntityUtils.toString(myEntity));
System.out.println(EntityUtils.toByteArray(myEntity).length);
stdout >
Content-Type: text/plain; charset=UTF-8
17
UTF-8
important message
17
1.1.5 确保资源释放
当响应实体完成之后,重要的是要确保所有的实体内容已被完全消耗,使该连接可以安全地返回到连接池,重新由连接管理器提供给后续请求使用。最简单的方法是调用HttpEntity#consumeContent()方法来消耗流上的所有可用的内容。当检测到内容已经达到流末尾的时候,HttpClient会自动释放底层连接返回到连接管理器。HttpEntity#consumeContent()方法多次调用也是安全的。
当只有小部分实体响应内容需要被检索和消费。其余内容,使用可重复的连接性能损失太大,可以简单地调用HttpUriRequest#abort()方法来终止请求。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int byteOne = instream.read();
int byteTwo = instream.read();
// Do not need the rest
httpget.abort();
}
该连接将不可重用,但是所有资源会被释放。
1.1.6 获取实体内容
获取实体内容推荐的方法是通过使用HttpEntity#getContent()或HttpEntity#writeTo(OutputStream中)方法。 HttpClient的还配备了EntityUtils类,它暴露了一些静态方法,以更轻松地阅读一个实体的内容或资料。使用这个类的方法和直接使用java.io.InputStream方法不同的是,他可以检索字符串中的全部内容机构/字节数组。强烈建议不要使用EntityUtils,除非响应实体来自一个可信赖的HTTP服务器和已知的有限长度。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
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
}
}
在某些情况下,实体内容可能需要能够读被多次读取。在这种情况下实体的内容必须以某种方式被缓冲在内存或磁盘上。最简单的方法是通过BufferedHttpEntity类来封装原始实体。原始实体内容可以从内存中的缓冲区来读取。其他方式封装实体都包含原始实体。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity = new BufferedHttpEntity(entity);
}
1.1.7 生产实体内容
HttpClient提供了一些类可以从HTTP连接内容中获得效地流。这些类的实例可以与实体内附如POST和PUT请求,以便为即将离任的HTTP请求附上实体内容。 HttpClient的为最常见的数据容器几类,如串,字节数组输入流和文件:StringEntity,ByteArrayEntity,InputStreamEntity和FileEntity。
File file = new File("somefile.txt");
FileEntity entity = new FileEntity(file, "text/plain; charset=\"UTF-8\"");
HttpPost httppost = new HttpPost("http://localhost/action.do");
httppost.setEntity(entity);
请注意InputStreamEntity是不可重复的,因为它只能从底层数据流中读取一次。一般来说,建议实现自定义HttpEntity类是自载的,而不是使用通用InputStreamEntity。 FileEntity可以是一个很好的起点。
1.1.7.1 动态内容实体
通常的HTTP实体需要在执行上下文的时候动态生成的。 HttpClient的提供使用EntityTemplate实体类和ContentProducer接口支持动态实体。内容制作是通过写需求的内容到一个输出流,每次请求的时候都会产生。因此,通过EntityTemplate创建实体通常是独立的,重复性好。
ContentProducer cp = new ContentProducer() {
public void writeTo(OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<response>");
writer.write(" <content>");
writer.write(" important stuff");
writer.write(" </content>");
writer.write("</response>");
writer.flush();
}
};
HttpEntity entity = new EntityTemplate(cp);
HttpPost httppost = new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
1.1.7.2 HTML forms
许多应用程序经常需要模拟一个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, "UTF-8");
HttpPost httppost = new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
这UrlEncodedFormEntity实例将使用 URL编码的编码参数,并出示下列内容:
param1=value1¶m2=value2
1.1.7.3 内容组块
一般来说,建议当HTTP消息的发送的时候让HttpClient的选择最合适的传输编码。这是可能的,但是,HttpClient首选通过设置HttpEntity#setChunked()为true设置编码。请注意的HttpClient将使用这个标志作为提示。当使用HTTP协议的版本不支持时候该值将被忽略时,如HTTP/1.0的块编码。
StringEntity entity = new StringEntity("important message",
"text/plain; charset=\"UTF-8\"");
entity.setChunked(true);
HttpPost httppost = new HttpPost("http://localhost/acrtion.do");
httppost.setEntity(entity);
1.1.8 响应处理程序
最简单和最方便的处理响应方式是通过使用ResponseHandler接口。这种方法完全免除了用户去担心连接管理。无论执行请求是否成功或导致异常,HttpClient的ResponseHandler会确保自动释放该连接回连接管理器。
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
ResponseHandler<byte[]> handler = new ResponseHandler<byte[]>() {
public byte[] handleResponse(
HttpResponse response) throws ClientProtocolException, IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toByteArray(entity);
} else {
return null;
}
}
};
byte[] response = httpclient.execute(httpget, handler);
1.2 HTTP的执行上下文
最初的HTTP被设计成一个无状态,响应,要求面向协议。然而,现实世界应用程序通常需要能够坚持通过几个逻辑上相关的请求响应交换状态信息。为了使应用程序能够保持状态,HttpClient允许 HTTP请求在一个特定的上下文中执行,被称为HTTP的上下文。如果一个逻辑同样的情况下连续请求之间重用,多个逻辑相关的要求可以参加到会话中,。 HTTP上下文功能类似于java.util.Map的<String, Object>。它只是一个任意命名的值的集合。可以在请求执行或者执行完毕之后校验下文的时候在添加属性参数到应用程序。
在HTTP请求执行的过程中HttpClient添加属性到执行上下文:
'http.connection':HttpConnection实例代表实际连接到目标服务器。
'http.target_host':HttpHost实例代表连接的目标。
'http.proxy_host':HttpHost实例代表连接代理,如果使用
'http.request':HttpRequest实例代表实际的HTTP请求。
'http.response':HttpResponse实例代表了实际的HTTP响应。
'http.request_sent':java.lang.Boolean的对象,表示该标志指示是否实际的要求已完全传输到连接的目标。
例如,想确定最后的重定向目标,一种方法可以在要求执行之后交验该http.target_host属性值:
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://www.google.com/");
HttpResponse response = httpclient.execute(httpget, localContext);
HttpHost target = (HttpHost) localContext.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
System.out.println("Final target: " + target);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
输出>
Final target: http://www.google.ch
1.3 异常处理
HttpClient的可以抛出两种例外情况:在I/O错误的时候java.io.IOException如socket timeout或者socket reset。HttpException 如违反了HTTP协议的HTTP错误故障。通常的I/O错误被视为非致命性和可恢复的,而HTTP协议错误被认为是致命的错误,不能自动收回。
1.3.1 HTTP传输安全
HTTP协议并没有适用所有应用。 HTTP是一个简单的请求/响应协议,最初旨在支持静态或动态生成的内容检索。它从未打算支持事务操作。例如,HTTP服务器将考虑其对履行合同的一部分,如果它在接收和处理请求成功,产生了反应,发出了一个状态代码返回给客户端。该服务器将不作任何尝试回滚事务,如果客户端无法接收的全部原因是读超时,要求取消或系统崩溃的反应。如果客户决定重试相同的请求,服务器将不可避免地最终执行相同的交易超过一次。在某些情况下,这可能导致应用数据损坏或不一致的应用现状。
虽然HTTP从来没有被设计成支持事务处理,它仍然可以作为传输协议为应用程序用执行关键任务。为了确保HTTP传输层安全,系统必须确保幂等的HTTP方法在应用层。
1.3.2 幂等方法
HTTP/1.1规范定义幂等方法,
方法含有幂等属性 指的是(除了错误或过期问题),N>0的相同请求和一个单独的请求是一样的。
换句话说,应用程序应该确保它准备处理的多个执行相同的方法的影响。这可以实现的,例如,通过提供一个独特的交易ID和避免同一逻辑操作执行的其他方式。
请注意,此问题不是特定的HttpClient。基于浏览器应用程序是完全符合相关的HTTP方法非幂等同样的问题。
HttpClient的假设非实体内附如GET和HEAD是幂等与实体内附 如POST和PUT方法不是。
1.3.3 异常自动恢复
默认情况下的HttpClient尝试自动恢复从I / O异常。默认的自动恢复机制是限于一个已知是安全的少数例外。
HttpClient的将不作任何尝试从任何逻辑或HTTP协议错误(从HttpException类派生的)的恢复。
HttpClient会自动重试那些被假定为幂等的方法。
HttpClient会自动重试的方法,传输失败异常的HTTP请求仍然被传输到目标服务器
HttpClient会自动重试那些已经完全传输到服务器的方法,但服务器没有响应的HTTP状态代码(服务器只是丢弃不发送任何东西连接)。在这种情况下,假设该请求没有被服务器和应用程序状态的处理并没有改变。如果这种假设可能不适用于您的应用程序的Web服务器是真正的目标,强烈建议提供一个自定义的异常处理程序。
1.3.4 请求重试处理程序
为了使自定义的异常恢复机制应该提供一个HttpRequestRetryHandler接口的实现。
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(
IOException exception,
int executionCount,
HttpContext context) {
if (executionCount >= 5) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof NoHttpResponseException) {
// Retry if the server dropped connection on us
return true;
}
if (exception instanceof SSLHandshakeException) {
// Do not retry on SSL handshake exception
return false;
}
HttpRequest request = (HttpRequest) context.getAttribute(
ExecutionContext.HTTP_REQUEST);
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// Retry if the request is considered idempotent
return true;
}
return false;
}
};
httpclient.setHttpRequestRetryHandler(myRetryHandler);
1.4 中止请求
在某些情况下执行HTTP请求未能完成预期的时间范围内由于对目标服务器或客户端发出太多的并发请求的高负荷。在这种情况下,可能有必要提前终止和解除封锁的要求执行的线程在I / O操作阻塞。 HTTP请求被处决的HttpClient可以在任何援引HttpUriRequest#abort()方法执行阶段中止。此方法是线程安全的,可以从任何线程调用。当一个HTTP请求被中止它的执行线程阻塞在一个I / O操作是保证解锁通过抛出一个InterruptedIOException
1.5 拦截HTTP协议
HTTP协议的拦截器是一个例程,实现了HTTP协议的具体内容。通常协议拦截行动后,预计一个特定标题或传入的消息头相关团体或填充一个特定的头或一组相关的头传出的消息。议定书拦截器还可以操纵的消息封闭的实体内容,透明的内容压缩/解压是一个很好的例子。通常这是通过使用'装饰'的模式,其中一个包装实体类是用来装饰的原始实体。几个协议拦截器可以组合成一个逻辑单元。
拦截器可以通过合作协议共享信息 - 如处理状态 - 通过HTTP的执行上下文。拦截器可以使用HTTP协议中的要求来存储一个或多个连续的请求处理状态。
通常在这种拦截器都执行不应该的问题,只要他们不依赖于特定国家的执行上下文秩序。如果协议拦截器有相互依存,因此必须在一个特定的顺序执行的,他们应该被添加到了他们的预期的执行顺序相同的顺序协议处理器。
议定书拦截器必须实现为线程安全的。同样到Servlet,协议拦截器不应使用实例变量,除非获得这些变量的同步。
这个例子说明本地上下文可用于保存请求的处理之间的连续状态:
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
AtomicInteger count = new AtomicInteger(1);
localContext.setAttribute("count", count);
httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AtomicInteger count = (AtomicInteger) context.getAttribute("count");
request.addHeader("Count", Integer.toString(count.getAndIncrement()));
}
});
HttpGet httpget = new HttpGet("http://localhost/");
for (int i = 0; i < 10; i++) {
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
}
1.6 HTTP parameters
HttpParams接口代表一个不可改变的值的集合,定义一个组件在运行时行为。在许多方面是相似的HttpContext HttpParams。两者的主要区别是他们在运行时使用。代表了两个接口是作为一个组织的键映射对象值对象的集合,而是为不同的目的:
HttpParams是为了包含简单的对象:整数,双打,字符串,集合和对象在运行时保持不变。
HttpParams预计将用在'写一次 - 准备许多'模式。 HttpContext的目的是包含很可能发生变异的HTTP消息处理过程中的复杂对象。
该HttpParams目的是确定了其他组件的行为。一般每个复杂的组件都有它自己的HttpParams对象。对HttpContext的目的,是代表了一个HTTP进程的执行状态。通常是相同的执行上下文之间共享许多合作对象。
1.6.1 参数层次
在HTTP请求的HttpRequest对象执行HttpParams当然是联系在一起的用于执行请求的HttpClient的实例HttpParams。这使得在HTTP请求参数水平接管HttpParams优先在HTTP客户端的水平。建议的做法是通过设置在HTTP客户端级别的共同所有的HTTP请求参数和选择性覆盖在HTTP请求级别的具体参数。
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_0);
httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET,
"UTF-8");
HttpGet httpget = new HttpGet("http://www.google.com/");
httpget.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_1);
httpget.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,
Boolean.FALSE);
httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.PROTOCOL_VERSION));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.HTTP_CONTENT_CHARSET));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.USE_EXPECT_CONTINUE));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.STRICT_TRANSFER_ENCODING));
}
});
输出>
HTTP/1.1
UTF-8
false
null
1.6.2 HTTP parameters beans
HttpParams接口为灵活性的实现在处理组件的配置。最重要的是,新的参数可以引进,而不会影响与旧版本的二进制兼容性。然而,HttpParams也具有一定的缺点相比,常规的Java bean:HttpParams不能直接投资框架组装使用。为了缓解这种限制,HttpClient的包括bean class,可以使用,以初始化HttpParams对象使用标准的Java bean约定的class数目。
HttpParams params = new BasicHttpParams();
HttpProtocolParamBean paramsBean = new HttpProtocolParamBean(params);
paramsBean.setVersion(HttpVersion.HTTP_1_1);
paramsBean.setContentCharset("UTF-8");
paramsBean.setUseExpectContinue(true);
System.out.println(params.getParameter(
CoreProtocolPNames.PROTOCOL_VERSION));
System.out.println(params.getParameter(
CoreProtocolPNames.HTTP_CONTENT_CHARSET));
System.out.println(params.getParameter(
CoreProtocolPNames.USE_EXPECT_CONTINUE));
System.out.println(params.getParameter(
CoreProtocolPNames.USER_AGENT));
输出>
HTTP/1.1
UTF-8
false
null
1.7 执行HTTP请求参数
这些参数可以影响到执行请求的过程:
'http.protocol.version':定义使用HTTP协议的版本,如果没有就请求对象明确。预计此参数类型ProtocolVersion价值。如果该参数没有设置HTTP/1.1中会被使用。
'http.protocol.element-charset':定义用于编码字符集是HTTP协议分子利用。此参数预计java.lang.String类型的值。如果此参数设置不美的ASCII将被使用。
'http.protocol.content-charset':定义为每默认用于内容主体编码字符集。此参数预计java.lang.String类型的值。如果该参数没有设置的ISO - 8859 - 1将被使用。
'http.useragent':定义了用户代理头的内容。此参数预计java.lang.String类型的值。如果此参数未设置,HttpClient的将自动生成一个值。
'http.protocol.strict-transfer-encoding':定义是否以无效传输编码头的反应,应予以拒绝。预计此参数类型java.lang.Boolean的价值。如果该参数没有设置无效的传输编码值将被忽略。
'http.protocol.expect-continue':激活期望:为封闭的方法,实体100继续握手。作者期望的目的:100继续握手,是让客户端发送一个请求主体请求消息,以确定是否愿意到原始服务器之前接受客户端发送请求的请求(根据请求头)机构。作者期望使用:100继续握手会导致一个附有如POST和PUT请求(实体显着的性能改进),要求在目标服务器的身份验证。预计:100继续握手应谨慎使用,因为它可能会导致与HTTP代理服务器的问题和不支持HTTP/1.1协议。预计此参数类型java.lang.Boolean的价值。如果该参数没有设置的HttpClient将尝试使用握手。
'http.protocol.wait-for-continue':定义了以毫秒为单位的时间最长的客户应该花费100继续等待响应。预计此参数类型java.lang.Integer价值。如果该参数没有设置的HttpClient将等待一段时间才能恢复请求的身体传送确认3秒。
HttpClient的最重要的功能是执行HTTP方法。一个HTTP方法的执行涉及到一个或多个HTTP请求或HTTP响应的交流,HttpClient通常是在内部处理的。用户将提供一个执行请求对象,HttpClient发送请求到目标服务器返回一个相应的响应对象,如果执行失败则抛出一个异常。所以,HttpClient API的主要切入点是HttpClient的接口,它定义了上述约定。
下面是一个请求执行过程中的最简单形式的例子:
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int l;
byte[] tmp = new byte[2048];
while ((l = instream.read(tmp)) != -1) {
}
}
1.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。所有的这些类均实现了HttpUriRequest接口,故可以作为execute的执行参数使用。请求URI是能够应用请求的统一资源标识符。 HTTP请求的URI包含一个协议计划protocol scheme,主机名host name,,可选的端口optional port,资源的路径resource path,可选的查询optional query和可选的片段optional fragment。
HttpGet httpget = new HttpGet(
"http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");
HttpClient提供了一系列实用的方法来简化创建和修改请求URI。
URI可以组装编程:
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
"q=httpclient&btnG=Google+Search&aq=f&oq=", null);
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
输出>
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
查询字符串也可以通过添加参数列表来生成:
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("q", "httpclient"));
qparams.add(new BasicNameValuePair("btnG", "Google Search"));
qparams.add(new BasicNameValuePair("aq", "f"));
qparams.add(new BasicNameValuePair("oq", null));
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
URLEncodedUtils.format(qparams, "UTF-8"), null);
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
输出>
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
1.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.1.3 Headers处理
一个HTTP消息可以包含一系列headers参数描述信息,例如内容长度,内容类型等。 HttpClient的提供方法来检索,添加,删除和枚举headers。
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);
输出>
Set-Cookie: c1=a; path=/; domain=localhost
Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
2
最有效获取所有的给定类型的headers方式是使用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());
}
输出>
Set-Cookie: c1=a; path=/; domain=localhost
Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
它还提供了方便的方法来解析HTTP消息的单个header元素
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]);
}
输出>
c1 = a
path=/
domain=localhost
c2 = b
path=/
c3 = c
domain=localhost
1.1.4 HTTP 实体
HTTP消息的可以进行内容实体和请求或响应关联。可以在一些要求和一些回应中找到实体,因为它们是可选的。实体内附与请求之中。 HTTP规范定义了两个实体内附方法:POST和PUT。响应通常将会附上一个内容实体。但是响应HEAD方法和 204 No Content, 304 Not Modified, 205 Reset Content responses 除外。
HttpClient的区分三种不同实体的地方在于内容来源于:
streamed流媒体:内容是从收到的流,或在运行中产生的。特别是包括被从HTTP响应收到的实体。流媒体的实体一般不可重复。
self-contained独立的:内容是在内存或以从一个连接或其他实体的独立获得的。独立的的实体,一般可重复的。这种类型的实体将主要用于内附在HTTP请求中。
wrapping包装:实体内容是从另一个实体获得。
当得到一个HTTP响应流的内容的时候,这种区分对于连接管理是很重要的。对于请求实体,通过应用程序来创建和只通过使用的HttpClient发送,流和自载之间差别很小。在这种情况下,建议考虑非重复的流实体,以及那些重复的自载实体。
1.1.4.1 重复实体
一个实体可以是可重复的,这意味着它的内容可以被读取一次以上。唯一有可能是的独立的实体(如ByteArrayEntity或StringEntity())
1.1.4.2 使用HTTP实体
由于一个实体能够表示二进制和字符的内容,它可以提供编码的支持(支持文字、IE和字符内容)。
这个实体在执行封闭内容的请求的时候或者在请求成功和响应返回成功的时候被创建。
若要读取从实体内容,一可以通过检索HttpEntity#getContent()方法,它返回一个java.io.InputStream,或一个可以提供一个输出流的HttpEntity#writeTo(OutputStream中)方法的输入流,这将返回已被写入给定的流的所有内容。
当通过传入的消息收到实体,方法HttpEntity#getContentType()和HttpEntity#getContentLength()方法可用于阅读通用元数据metadata,如Content-Type,Content-Length headers(如果可用)。由于Content-Type header可以包含一个像text/plain或者text/html的文本mime-types的character encoding,HttpEntity#getContentEncoding()方法用来读取此信息。如果headers是不可用,返回的长度是-1,content type并为NUL。如果Content – Type header可用,将返回一个header对象。
当创建了一个即将卸任的消息实体,该meta data必须提供由该实体的创造者。
StringEntity myEntity = new StringEntity("important message",
"UTF-8");
System.out.println(myEntity.getContentType());
System.out.println(myEntity.getContentLength());
System.out.println(EntityUtils.getContentCharSet(myEntity));
System.out.println(EntityUtils.toString(myEntity));
System.out.println(EntityUtils.toByteArray(myEntity).length);
stdout >
Content-Type: text/plain; charset=UTF-8
17
UTF-8
important message
17
1.1.5 确保资源释放
当响应实体完成之后,重要的是要确保所有的实体内容已被完全消耗,使该连接可以安全地返回到连接池,重新由连接管理器提供给后续请求使用。最简单的方法是调用HttpEntity#consumeContent()方法来消耗流上的所有可用的内容。当检测到内容已经达到流末尾的时候,HttpClient会自动释放底层连接返回到连接管理器。HttpEntity#consumeContent()方法多次调用也是安全的。
当只有小部分实体响应内容需要被检索和消费。其余内容,使用可重复的连接性能损失太大,可以简单地调用HttpUriRequest#abort()方法来终止请求。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int byteOne = instream.read();
int byteTwo = instream.read();
// Do not need the rest
httpget.abort();
}
该连接将不可重用,但是所有资源会被释放。
1.1.6 获取实体内容
获取实体内容推荐的方法是通过使用HttpEntity#getContent()或HttpEntity#writeTo(OutputStream中)方法。 HttpClient的还配备了EntityUtils类,它暴露了一些静态方法,以更轻松地阅读一个实体的内容或资料。使用这个类的方法和直接使用java.io.InputStream方法不同的是,他可以检索字符串中的全部内容机构/字节数组。强烈建议不要使用EntityUtils,除非响应实体来自一个可信赖的HTTP服务器和已知的有限长度。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
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
}
}
在某些情况下,实体内容可能需要能够读被多次读取。在这种情况下实体的内容必须以某种方式被缓冲在内存或磁盘上。最简单的方法是通过BufferedHttpEntity类来封装原始实体。原始实体内容可以从内存中的缓冲区来读取。其他方式封装实体都包含原始实体。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity = new BufferedHttpEntity(entity);
}
1.1.7 生产实体内容
HttpClient提供了一些类可以从HTTP连接内容中获得效地流。这些类的实例可以与实体内附如POST和PUT请求,以便为即将离任的HTTP请求附上实体内容。 HttpClient的为最常见的数据容器几类,如串,字节数组输入流和文件:StringEntity,ByteArrayEntity,InputStreamEntity和FileEntity。
File file = new File("somefile.txt");
FileEntity entity = new FileEntity(file, "text/plain; charset=\"UTF-8\"");
HttpPost httppost = new HttpPost("http://localhost/action.do");
httppost.setEntity(entity);
请注意InputStreamEntity是不可重复的,因为它只能从底层数据流中读取一次。一般来说,建议实现自定义HttpEntity类是自载的,而不是使用通用InputStreamEntity。 FileEntity可以是一个很好的起点。
1.1.7.1 动态内容实体
通常的HTTP实体需要在执行上下文的时候动态生成的。 HttpClient的提供使用EntityTemplate实体类和ContentProducer接口支持动态实体。内容制作是通过写需求的内容到一个输出流,每次请求的时候都会产生。因此,通过EntityTemplate创建实体通常是独立的,重复性好。
ContentProducer cp = new ContentProducer() {
public void writeTo(OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<response>");
writer.write(" <content>");
writer.write(" important stuff");
writer.write(" </content>");
writer.write("</response>");
writer.flush();
}
};
HttpEntity entity = new EntityTemplate(cp);
HttpPost httppost = new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
1.1.7.2 HTML forms
许多应用程序经常需要模拟一个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, "UTF-8");
HttpPost httppost = new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
这UrlEncodedFormEntity实例将使用 URL编码的编码参数,并出示下列内容:
param1=value1¶m2=value2
1.1.7.3 内容组块
一般来说,建议当HTTP消息的发送的时候让HttpClient的选择最合适的传输编码。这是可能的,但是,HttpClient首选通过设置HttpEntity#setChunked()为true设置编码。请注意的HttpClient将使用这个标志作为提示。当使用HTTP协议的版本不支持时候该值将被忽略时,如HTTP/1.0的块编码。
StringEntity entity = new StringEntity("important message",
"text/plain; charset=\"UTF-8\"");
entity.setChunked(true);
HttpPost httppost = new HttpPost("http://localhost/acrtion.do");
httppost.setEntity(entity);
1.1.8 响应处理程序
最简单和最方便的处理响应方式是通过使用ResponseHandler接口。这种方法完全免除了用户去担心连接管理。无论执行请求是否成功或导致异常,HttpClient的ResponseHandler会确保自动释放该连接回连接管理器。
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
ResponseHandler<byte[]> handler = new ResponseHandler<byte[]>() {
public byte[] handleResponse(
HttpResponse response) throws ClientProtocolException, IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toByteArray(entity);
} else {
return null;
}
}
};
byte[] response = httpclient.execute(httpget, handler);
1.2 HTTP的执行上下文
最初的HTTP被设计成一个无状态,响应,要求面向协议。然而,现实世界应用程序通常需要能够坚持通过几个逻辑上相关的请求响应交换状态信息。为了使应用程序能够保持状态,HttpClient允许 HTTP请求在一个特定的上下文中执行,被称为HTTP的上下文。如果一个逻辑同样的情况下连续请求之间重用,多个逻辑相关的要求可以参加到会话中,。 HTTP上下文功能类似于java.util.Map的<String, Object>。它只是一个任意命名的值的集合。可以在请求执行或者执行完毕之后校验下文的时候在添加属性参数到应用程序。
在HTTP请求执行的过程中HttpClient添加属性到执行上下文:
'http.connection':HttpConnection实例代表实际连接到目标服务器。
'http.target_host':HttpHost实例代表连接的目标。
'http.proxy_host':HttpHost实例代表连接代理,如果使用
'http.request':HttpRequest实例代表实际的HTTP请求。
'http.response':HttpResponse实例代表了实际的HTTP响应。
'http.request_sent':java.lang.Boolean的对象,表示该标志指示是否实际的要求已完全传输到连接的目标。
例如,想确定最后的重定向目标,一种方法可以在要求执行之后交验该http.target_host属性值:
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://www.google.com/");
HttpResponse response = httpclient.execute(httpget, localContext);
HttpHost target = (HttpHost) localContext.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
System.out.println("Final target: " + target);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
输出>
Final target: http://www.google.ch
1.3 异常处理
HttpClient的可以抛出两种例外情况:在I/O错误的时候java.io.IOException如socket timeout或者socket reset。HttpException 如违反了HTTP协议的HTTP错误故障。通常的I/O错误被视为非致命性和可恢复的,而HTTP协议错误被认为是致命的错误,不能自动收回。
1.3.1 HTTP传输安全
HTTP协议并没有适用所有应用。 HTTP是一个简单的请求/响应协议,最初旨在支持静态或动态生成的内容检索。它从未打算支持事务操作。例如,HTTP服务器将考虑其对履行合同的一部分,如果它在接收和处理请求成功,产生了反应,发出了一个状态代码返回给客户端。该服务器将不作任何尝试回滚事务,如果客户端无法接收的全部原因是读超时,要求取消或系统崩溃的反应。如果客户决定重试相同的请求,服务器将不可避免地最终执行相同的交易超过一次。在某些情况下,这可能导致应用数据损坏或不一致的应用现状。
虽然HTTP从来没有被设计成支持事务处理,它仍然可以作为传输协议为应用程序用执行关键任务。为了确保HTTP传输层安全,系统必须确保幂等的HTTP方法在应用层。
1.3.2 幂等方法
HTTP/1.1规范定义幂等方法,
方法含有幂等属性 指的是(除了错误或过期问题),N>0的相同请求和一个单独的请求是一样的。
换句话说,应用程序应该确保它准备处理的多个执行相同的方法的影响。这可以实现的,例如,通过提供一个独特的交易ID和避免同一逻辑操作执行的其他方式。
请注意,此问题不是特定的HttpClient。基于浏览器应用程序是完全符合相关的HTTP方法非幂等同样的问题。
HttpClient的假设非实体内附如GET和HEAD是幂等与实体内附 如POST和PUT方法不是。
1.3.3 异常自动恢复
默认情况下的HttpClient尝试自动恢复从I / O异常。默认的自动恢复机制是限于一个已知是安全的少数例外。
HttpClient的将不作任何尝试从任何逻辑或HTTP协议错误(从HttpException类派生的)的恢复。
HttpClient会自动重试那些被假定为幂等的方法。
HttpClient会自动重试的方法,传输失败异常的HTTP请求仍然被传输到目标服务器
HttpClient会自动重试那些已经完全传输到服务器的方法,但服务器没有响应的HTTP状态代码(服务器只是丢弃不发送任何东西连接)。在这种情况下,假设该请求没有被服务器和应用程序状态的处理并没有改变。如果这种假设可能不适用于您的应用程序的Web服务器是真正的目标,强烈建议提供一个自定义的异常处理程序。
1.3.4 请求重试处理程序
为了使自定义的异常恢复机制应该提供一个HttpRequestRetryHandler接口的实现。
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(
IOException exception,
int executionCount,
HttpContext context) {
if (executionCount >= 5) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof NoHttpResponseException) {
// Retry if the server dropped connection on us
return true;
}
if (exception instanceof SSLHandshakeException) {
// Do not retry on SSL handshake exception
return false;
}
HttpRequest request = (HttpRequest) context.getAttribute(
ExecutionContext.HTTP_REQUEST);
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// Retry if the request is considered idempotent
return true;
}
return false;
}
};
httpclient.setHttpRequestRetryHandler(myRetryHandler);
1.4 中止请求
在某些情况下执行HTTP请求未能完成预期的时间范围内由于对目标服务器或客户端发出太多的并发请求的高负荷。在这种情况下,可能有必要提前终止和解除封锁的要求执行的线程在I / O操作阻塞。 HTTP请求被处决的HttpClient可以在任何援引HttpUriRequest#abort()方法执行阶段中止。此方法是线程安全的,可以从任何线程调用。当一个HTTP请求被中止它的执行线程阻塞在一个I / O操作是保证解锁通过抛出一个InterruptedIOException
1.5 拦截HTTP协议
HTTP协议的拦截器是一个例程,实现了HTTP协议的具体内容。通常协议拦截行动后,预计一个特定标题或传入的消息头相关团体或填充一个特定的头或一组相关的头传出的消息。议定书拦截器还可以操纵的消息封闭的实体内容,透明的内容压缩/解压是一个很好的例子。通常这是通过使用'装饰'的模式,其中一个包装实体类是用来装饰的原始实体。几个协议拦截器可以组合成一个逻辑单元。
拦截器可以通过合作协议共享信息 - 如处理状态 - 通过HTTP的执行上下文。拦截器可以使用HTTP协议中的要求来存储一个或多个连续的请求处理状态。
通常在这种拦截器都执行不应该的问题,只要他们不依赖于特定国家的执行上下文秩序。如果协议拦截器有相互依存,因此必须在一个特定的顺序执行的,他们应该被添加到了他们的预期的执行顺序相同的顺序协议处理器。
议定书拦截器必须实现为线程安全的。同样到Servlet,协议拦截器不应使用实例变量,除非获得这些变量的同步。
这个例子说明本地上下文可用于保存请求的处理之间的连续状态:
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
AtomicInteger count = new AtomicInteger(1);
localContext.setAttribute("count", count);
httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AtomicInteger count = (AtomicInteger) context.getAttribute("count");
request.addHeader("Count", Integer.toString(count.getAndIncrement()));
}
});
HttpGet httpget = new HttpGet("http://localhost/");
for (int i = 0; i < 10; i++) {
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
}
1.6 HTTP parameters
HttpParams接口代表一个不可改变的值的集合,定义一个组件在运行时行为。在许多方面是相似的HttpContext HttpParams。两者的主要区别是他们在运行时使用。代表了两个接口是作为一个组织的键映射对象值对象的集合,而是为不同的目的:
HttpParams是为了包含简单的对象:整数,双打,字符串,集合和对象在运行时保持不变。
HttpParams预计将用在'写一次 - 准备许多'模式。 HttpContext的目的是包含很可能发生变异的HTTP消息处理过程中的复杂对象。
该HttpParams目的是确定了其他组件的行为。一般每个复杂的组件都有它自己的HttpParams对象。对HttpContext的目的,是代表了一个HTTP进程的执行状态。通常是相同的执行上下文之间共享许多合作对象。
1.6.1 参数层次
在HTTP请求的HttpRequest对象执行HttpParams当然是联系在一起的用于执行请求的HttpClient的实例HttpParams。这使得在HTTP请求参数水平接管HttpParams优先在HTTP客户端的水平。建议的做法是通过设置在HTTP客户端级别的共同所有的HTTP请求参数和选择性覆盖在HTTP请求级别的具体参数。
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_0);
httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET,
"UTF-8");
HttpGet httpget = new HttpGet("http://www.google.com/");
httpget.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_1);
httpget.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,
Boolean.FALSE);
httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.PROTOCOL_VERSION));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.HTTP_CONTENT_CHARSET));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.USE_EXPECT_CONTINUE));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.STRICT_TRANSFER_ENCODING));
}
});
输出>
HTTP/1.1
UTF-8
false
null
1.6.2 HTTP parameters beans
HttpParams接口为灵活性的实现在处理组件的配置。最重要的是,新的参数可以引进,而不会影响与旧版本的二进制兼容性。然而,HttpParams也具有一定的缺点相比,常规的Java bean:HttpParams不能直接投资框架组装使用。为了缓解这种限制,HttpClient的包括bean class,可以使用,以初始化HttpParams对象使用标准的Java bean约定的class数目。
HttpParams params = new BasicHttpParams();
HttpProtocolParamBean paramsBean = new HttpProtocolParamBean(params);
paramsBean.setVersion(HttpVersion.HTTP_1_1);
paramsBean.setContentCharset("UTF-8");
paramsBean.setUseExpectContinue(true);
System.out.println(params.getParameter(
CoreProtocolPNames.PROTOCOL_VERSION));
System.out.println(params.getParameter(
CoreProtocolPNames.HTTP_CONTENT_CHARSET));
System.out.println(params.getParameter(
CoreProtocolPNames.USE_EXPECT_CONTINUE));
System.out.println(params.getParameter(
CoreProtocolPNames.USER_AGENT));
输出>
HTTP/1.1
UTF-8
false
null
1.7 执行HTTP请求参数
这些参数可以影响到执行请求的过程:
'http.protocol.version':定义使用HTTP协议的版本,如果没有就请求对象明确。预计此参数类型ProtocolVersion价值。如果该参数没有设置HTTP/1.1中会被使用。
'http.protocol.element-charset':定义用于编码字符集是HTTP协议分子利用。此参数预计java.lang.String类型的值。如果此参数设置不美的ASCII将被使用。
'http.protocol.content-charset':定义为每默认用于内容主体编码字符集。此参数预计java.lang.String类型的值。如果该参数没有设置的ISO - 8859 - 1将被使用。
'http.useragent':定义了用户代理头的内容。此参数预计java.lang.String类型的值。如果此参数未设置,HttpClient的将自动生成一个值。
'http.protocol.strict-transfer-encoding':定义是否以无效传输编码头的反应,应予以拒绝。预计此参数类型java.lang.Boolean的价值。如果该参数没有设置无效的传输编码值将被忽略。
'http.protocol.expect-continue':激活期望:为封闭的方法,实体100继续握手。作者期望的目的:100继续握手,是让客户端发送一个请求主体请求消息,以确定是否愿意到原始服务器之前接受客户端发送请求的请求(根据请求头)机构。作者期望使用:100继续握手会导致一个附有如POST和PUT请求(实体显着的性能改进),要求在目标服务器的身份验证。预计:100继续握手应谨慎使用,因为它可能会导致与HTTP代理服务器的问题和不支持HTTP/1.1协议。预计此参数类型java.lang.Boolean的价值。如果该参数没有设置的HttpClient将尝试使用握手。
'http.protocol.wait-for-continue':定义了以毫秒为单位的时间最长的客户应该花费100继续等待响应。预计此参数类型java.lang.Integer价值。如果该参数没有设置的HttpClient将等待一段时间才能恢复请求的身体传送确认3秒。
发表评论
-
MyEclipse中启动OutOfMemoryError: PermGen space
2011-12-16 20:57 1527在项目开发中有多个项目需要在MyEclipse中 ... -
jboss4 java.lang.OutOfMemoryError: PermGen space(jboss 4.2.3.GA)
2011-12-08 17:18 1957jboss 出现异常: java.lang.OutOfMem ... -
jboss4 配置多个oracle数据源
2011-12-08 15:44 1426jboss4 配置多个oracle数据源源的方法,在一个应用中 ... -
Jboss配置的连接池报 org.jboss.deployment.DeploymentException: Error during deploy;
2011-12-08 15:32 5497jboss 下部署程序,启动时报: org.jboss.de ... -
Eclipse调试tomcat时报45秒超时
2011-07-01 15:00 1462在Eclipse调试tomcat时突然出现: Serve ... -
proxy: No protocol handler was valid for the URL错误解决办法
2011-05-31 10:17 3255用apache做负载均衡时遇到了如题的错误。 proxy: N ... -
tomcat 6配置本机域名
2011-05-19 17:09 15951:在本机上设置自己的测试域名 打开C:\Windows\Sy ... -
如何利用HTTP缓存提高网页性能
2011-05-17 18:14 894http://blogold.chinaunix.net/u1 ... -
HTTP头的Expires与Cache-control
2011-05-17 18:13 955HTTP头的Expires与Cache-control 1. ... -
Squid和Apache中的max-age与Expires的分别
2011-05-17 18:12 1406本文链接: http://www.php-oa.com/200 ... -
Apache mod_jk 的JkMount与JkUnMount差别
2011-05-11 14:47 1992Apache mod_jk 的JkMount与JkUnMoun ... -
HTTP 1.1状态代码及其含义
2011-05-10 20:51 776HTTP 1.1状态代码及其含义 100 Continue ... -
windows 下apahce (2.2.17版)+tomcat(6.0.20)+mod_jk 最简单整合
2011-05-05 15:15 13041、环境 Apache : apache_2.2.17-wi ...
相关推荐
一、HttpClient基础 HttpClient的核心类是`org.apache.http.client.HttpClient`,它是执行HTTP请求的入口点。创建HttpClient实例后,可以调用`execute()`方法发起GET、POST等不同类型的HTTP请求。例如: ```java ...
1. **HttpClient基础知识**: - HttpClient是Apache的一个开源项目,提供了强大的HTTP协议处理能力,支持GET、POST、PUT等多种HTTP请求方法。 - HttpClient提供了一个基于连接池的连接管理器,可以有效地管理HTTP...
HttpClient基础 #### 1.1 请求执行 - **HTTP请求**:HttpClient用于构建和发送HTTP请求。 - **HTTP响应**:描述了对来自服务器的响应的处理,包括读取状态行、头部信息和主体内容。 - **操作消息头**:说明了如何...
三、HttpClient基础使用 1. 创建HttpClient实例 HttpClient的核心是`HttpClient`对象,我们可以通过`HttpClients.createDefault()`创建一个默认配置的实例。例如: ```java CloseableHttpClient httpClient = ...
1.HttpClient基础 1.1 请求执行 - 1.1.1 HTTP请求:讲解了如何创建和配置HTTP请求,包括请求的方法(如GET、POST、PUT、DELETE等)、路径、查询参数、请求头等。 - 1.1.2 HTTP响应:如何处理HTTP响应,包括状态码、...
一、HttpClient基础 HttpClient库提供了一套完整的API,允许我们构建复杂的HTTP请求。它支持GET、POST、PUT等多种HTTP方法,以及Cookie管理、重定向处理、身份验证等功能。PostMethod是HttpClient中用于执行POST请求...
1. **HttpClient基础**:HttpClient 4.x的初始化和配置,包括创建HttpClient实例,设置连接池,处理重定向和重试策略。 2. **请求构造**:如何构建HTTP请求,包括添加请求头、设置请求方法、携带请求体等。比如,...
1. HttpClient基础 1.1 请求执行 1.1.1 HTTP请求:HttpClient支持创建和配置HTTP请求,包括GET、POST、PUT、DELETE等方法。 1.1.2 HTTP响应:处理从服务器返回的响应,理解响应码和响应体。 1.1.3 消息头处理:...
一、HttpClient基础 HttpClient的主要组件包括`HttpClient`、`HttpRequest`、`HttpResponse`和`HttpEntity`。`HttpClient`是整个HTTP操作的发起者,负责管理连接和执行请求。`HttpRequest`代表了HTTP请求,`...
httpclient必备基础jar包,HttpClient client=new HttpClint();1.3版本!
三、HttpClient基础用法 1. 创建HttpClient实例: HttpClient的实例化通常是通过`HttpClientBuilder`完成的,可以设置各种参数,如连接超时、重试策略等。 2. 发送GET请求: 使用`HttpGet`类创建GET请求,并通过`...
除了基础的GET和POST请求,HttpClient还提供了许多高级特性,如: - **重试策略**:通过`HttpRequestRetryHandler`可以定制请求失败后的重试行为。 - **连接管理**:`PoolingHttpClientConnectionManager`允许配置...
一、HttpClient基础 HttpClient库提供了一套完整的API,允许开发者构建复杂的HTTP请求,包括GET、POST、PUT等多种HTTP方法。它支持异步和同步操作,具有可扩展性和灵活性,可以处理重定向、cookies、认证等高级特性...
例如,我们可以通过以下方式发送一个GET请求: CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet("https://example.com/"); CloseableHttpResponse response = ...
它是HttpClient进行网络通信的基础。 7. `httpmime-4.x.x.jar`: 这个库扩展了HttpClient,支持MIME类型的HTTP请求,如上传文件、处理多部分表单数据等。 8. `log4j-1.2.x.jar`: 这是一个日志记录框架,通常与...
同时,HttpClient依赖于HttpCore库,这是Apache提供的基础HTTP协议处理组件,httpcore-4.4.1.jar即为该组件的4.4.1版本,提供了HTTP连接管理、请求/响应模型等核心功能。 **一、HttpClient基本概念** 1. **...
1. **HttpClient对象**:HttpClient是所有操作的基础,它代表一个HTTP客户端,可以配置连接管理器、请求执行器等组件。 2. **HttpMethod**:HttpClient提供了多种HttpMethod子类,如GetMethod、PostMethod等,分别...
2. `httpcore-4.x.x.jar`: 这是HttpClient的基础组件,提供了网络通信的基本功能,如套接字连接和输入/输出流处理。 3. `httpmime-4.x.x.jar`: 这个库扩展了HttpClient,支持在HTTP请求中处理MIME类型的数据,比如...
2. **HttpCore库**:`httpcore-x.x.x.jar`是HttpClient的基础组件,提供HTTP协议的基本操作,如连接管理、请求/响应处理等。HttpClient依赖HttpCore来处理底层的网络通信。 3. **HTTP协议支持**:HttpClient支持...