介绍

Jetty HTTP client模块提供易用的API、工具类和一个高性能、异步的实现来运行HTTP和HTTPS请求。

Jetty HTTP client模块要求Java版本号1.7或者更高,Java 1.8的应用能用lambda表达式在一些HTTP client API中。

Jetty HTTP client被实现和提供一个异步的API。不会由于I/O时间堵塞,因此使它在线程的利用上更有效率,并不是常适合用于负载測试和并行计算。

然而,有时你全部须要做的是对一个资源运行一个GET请求,HTTP client也提供了一个异步API。发起请求的线程将堵塞直到请求处理完毕。

在外部来看。Jetty HTTP client提供:

 1)重定向支持;重定向编码比如302或者303被自己主动尾随。

 2)Cookies支持;被服务端送的cookies在匹配的请求中被送回到服务端。

 3)认证支持;HTTP “Basic”和“Digest”热症被支持。其他的能够添加;

 4)前转协议支持。

初始化

基本的类的名称是org.eclipse.jetty.client.HttpClient,同Jetty 7和Jetty 8中一样(尽管它和Jetty 7和Jetty 8中的同名类不是向后兼容的)。

你能够将一个HttpClient实例看作一个浏览器实例。像一个浏览器,它能发起请求到不同的域,它管理重定向、cookies和认证,你能用代理配置它。而且他提供给你你发起的请求的响应。

为了使用HttpClient,你必须初始化它、配置它、然后启动它:

  1. // Instantiate HttpClient
  2. HttpClient httpClient = new HttpClient();
  3.  
  4. // Configure HttpClient, for example:
  5. httpClient.setFollowRedirects(false);
  6.  
  7. // Start HttpClient
  8. httpClient.start();

你能创建多个HttpClient的实例。原因可能是你想指定不同的配置參数(比如。一个实例被配置为前转代理而还有一个不是),或者由于你想有两个实例履行象两个不同的浏览器,因此有不同的cookies、不同的认证证书等等。

当你用參数构造器创建一个HttpClient实例时,你仅能履行简单的HTTP请求,而且你将不能履行HTTPS请求。

为了履行HTTPS请求。你首先应该创建一个SslContextFactory,配置它。而且传递它到HttpClient的构造器。当用一个SslContextFactory创建时。HttpClient将能履行HTTP和HTTPS请求到不论什么域。

  1. // Instantiate and configure the SslContextFactory
  2. SslContextFactory sslContextFactory = new SslContextFactory();
  3.  
  4. // Instantiate HttpClient with the SslContextFactory
  5. HttpClient httpClient = new HttpClient(sslContextFactory);
  6.  
  7. // Configure HttpClient, for example:
  8. httpClient.setFollowRedirects(false);
  9.  
  10. // Start HttpClient
  11. httpClient.start();

API介绍

堵塞API

为了履行一个HTTP请求更简单的方法是:

  1. ContentResponse response = httpClient.GET(<a target=_blank href="http://domain.com/path?query">http://domain.com/path?query</a>);

方法HttpClient.GET(...)履行一个HTTP GET请求到一个给定的URI。成功后返回一个ContentResponse。

ContentResponse对象包括HTTP响应信息:状态码、headers和可能的内容。内容长度默认被限制到2M;以下“响应内容处理”会介绍怎么处理更大的内容。

假设你想定制请求,比如通过发起一个HEAD请求取代一个GET,而且仿真一个浏览器用户代理。你能使用这样的方式:

  1. ContentResponse response = httpClient.newRequest("http://domain.com/path?query")
  2. .method(HttpMethod.HEAD)
  3. .agent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0")
  4. .send();

以下是採用简写的方式:

  1. Request request = httpClient.newRequest("http://domain.com/path?query");
  2. request.method(HttpMethod.HEAD);
  3. request.agent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0");
  4. ContentResponse response = request.send();

你首先用httpClient.newRequest(...)创建了一个请求对象。然后你定制它。

当请求对象被定制后。你调用Request.send()。当请求处理玩陈过后,返回ContentResponse。

简单的POST请求也有一个简写的方法:

  1. ContentResponse response = httpClient.POST("http://domain.com/entity/1")
  2. .param("p", "value")
  3. .send();

POST的參数值被自己主动的URL编码。

Jetty HTTP client自己主动地尾随重定向,因此自己主动地处理这样的典型的web模式POST/Redirect/GET,而且响应对象包括了GET请求的响应的内容。尾随重定向是一个特征,你能针对每一个请求或者全局来激活/停止。

文件上传也须要一行,使用JDK 7的java.nio.file类:

  1. ContentResponse response = httpClient.newRequest("http://domain.com/upload")
  2. .file(Paths.get("file_to_upload.txt"), "text/plain")
  3. .send();

也能够添加一个超时时间:

  1. ContentResponse response = httpClient.newRequest("http://domain.com/path?query")
  2. .timeout(5, TimeUnit.SECONDS)
  3. .send();

在上面的样例中,当超过5秒后,请求被终止并抛出一个java.util.concurrent.TimeoutException异常。

异步API

到眼下为止我们展示了怎么使用Jetty HTTP client的堵塞API,即发起请求的线程堵塞直到请求被处理完毕。

在这节我们将看看Jetty HTTP client的异步、非堵塞API,很适合大数据下载、请求/响应的并行处理、在性能和有效的线程、资源的利用是一个关键因素的全部场合。

异步API在请求和响应处理的各个阶段都依赖于对回调listener的调用。这些listener被应用实现。能够履行不论什么应用逻辑。实如今处理请求或者响应的线程中调用这些listener。因此,假设在这些listener中的应用代码须要花费较长时间,请求或者响应的处理将被堵塞。

假设你须要在一个listener内运行耗时操作,你必须使用你自己的线程,而且记住要深度拷贝listener提供的不论什么数据,由于当listener返回后,这些数据可能回收/清除/销毁。

请求和响应在两个不同的线程中运行,因此能够并行的运行。这个并行处理的一个典型样例是一个回显server。一个大的上传和大的回显下载同一时候进行。

注意。记住响应能够在请求之前被处理和完毕。一个典型的样例是被server触发一个高速响应的一个大的上载(比如一个error):当请求内容任然在上载时。响应已经到达和被完毕了。

应用线程调用Request.send(CompleteListener)履行请求的处理。直到或者请求被充分地处理或者因为堵塞在I/O而返回(因此从不堵塞)。假设它将堵塞在I/O,线程请求I/O系统当I/O完毕时发出一个事件,然后返回。

当如此一个事件被触发。一个来自HttpClient线程池的线程将恢复响应的处理。

响应被线程处理。这些线程或者是触发字节码已经被准备好的I/O系统线程,或者是来自HttpClient线程池的一个线程(这通过HttpClient.isDispatchIO()属性控制)。响应持续处理直到响应被处理完毕或者堵塞在I/O。假设它堵塞在I/O,线程请求I/O系统在I/O准备好后发出一个时间,然后返回。

当如此一个事件被触发。一个来自HttpClient线程池的线程将恢复响应的处理。

当请求和响应都处理完毕后。完毕最后处理的线程(一般是处理响应的线程,但也可能是处理请求的线程——假设请求比响应的处理花费很多其它的时间)将取下一个请求进行处理。

一个抛弃响应内容的异步GET请求能这样实现:

  1. httpClient.newRequest("http://domain.com/path")
  2. .send(new Response.CompleteListener()
  3. {
  4. @Override
  5. public void onComplete(Result result)
  6. {
  7. // Your logic here
  8. }
  9. });

方法Request.send(Response.CompleteListener)返回void,而且不堵塞;当请求/响应处理完毕后Response.CompleteListener将被通知,result參数能够获取到响应对象。

你能用JDK 8的lambda表达式写相同的代码:

  1. httpClient.newRequest("http://domain.com/path")
  2. .send((result) -> { /* Your logic here */ });

你也能为它指定一个总的超时时间:

  1. Request request = httpClient.newRequest("http://domain.com/path")
  2. .timeout(3, TimeUnit.SECONDS)
  3. .send(new Response.CompleteListener()
  4. {
  5. @Override
  6. public void onComplete(Result result)
  7. {
  8. // Your logic here
  9. }
  10. });

上面的样例为请求/响应处理指定了一个超时时间3秒。

HTTP client API广泛的使用listener为全部可能的请求和响应时间提供钩子,在JDK 8的lambda表达式中。他们变得更易使用:

  1. httpClient.newRequest("http://domain.com/path")
  2. // Add request hooks
  3. .onRequestQueued((request) -> { ... })
  4. .onRequestBegin((request) -> { ... })
  5. ... // More request hooks available
  6.  
  7. // Add response hooks
  8. .onResponseBegin((response) -> { ... })
  9. .onResponseHeaders((response) -> { ... })
  10. .onResponseContent((response, buffer) -> { ... })
  11. ... // More response hooks available
  12.  
  13. .send((result) -> { ... });

这使得Jetty HTTP client非常适合HTTP负载測试,比如。你能精确的知道请求/响应处理的每一步花费的时间(因此知道请求/响应时间被真正消耗的地方)。

了解请求事件请查看Request.Listener,了解响应事件请查看Response.Listener。

内容处理

请求内容处理

Jetty HTTP client提供了很多现成的工具类处理请求内容。

你能提供这些格式的请求内容:String、byte[]、ByteBuffer、java.nio.file.Path、 InputStream,并提供你的org.eclipse.jetty.client.api.ContentProvider的实现。

以下是一个样例。使用java.nio.file.Paths提供请求内容:

  1. ContentResponse response = httpClient.newRequest("http://domain.com/upload")
  2. .file(Paths.get("file_to_upload.txt"), "text/plain")
  3. .send();

这等价于这样使用PathContentProvider工具类:

  1. ContentResponse response = httpClient.newRequest("http://domain.com/upload")
  2. .content(new PathContentProvider(Paths.get("file_to_upload.txt")), "text/plain")
  3. .send();

相同。你能通过InputStreamContentProvider工具类使用FileInputStream:

  1. ContentResponse response = httpClient.newRequest("http://domain.com/upload")
  2. .content(new InputStreamContentProvider(new FileInputStream("file_to_upload.txt")), "text/plain")
  3. .send();

因为InputStream是堵塞的,因此请求的发送将堵塞,能够考虑使用异步API。

假设你已经将内容读到内存中。你能使用BytesContentProvider工具类将它作为byte[]传入:

  1. byte[] bytes = ...;
  2. ContentResponse response = httpClient.newRequest("http://domain.com/upload")
  3. .content(new BytesContentProvider(bytes), "text/plain")
  4. .send();

假设请求内容不是马上可用的,你能用DeferredContentProvider:

  1. DeferredContentProvider content = new DeferredContentProvider();
  2. httpClient.newRequest("http://domain.com/upload")
  3. .content(content)
  4. .send(new Response.CompleteListener()
  5. {
  6. @Override
  7. public void onComplete(Result result)
  8. {
  9. // Your logic here
  10. }
  11. });
  12.  
  13. // Content not available yet here
  14.  
  15. ...
  16.  
  17. // An event happens, now content is available
  18. byte[] bytes = ...;
  19. content.offer(ByteBuffer.wrap(bytes));
  20.  
  21. ...
  22.  
  23. // All content has arrived
  24. content.close();

提供请求内容的还有一个方法是使用OutputStreamContentProvider,当请求内容可用时同意应用写请求内容到OutputStreamContentProvider提供的OutputStream:

  1. OutputStreamContentProvider content = new OutputStreamContentProvider();
  2.  
  3. // Use try-with-resources to close the OutputStream when all content is written
  4. try (OutputStream output = content.getOutputStream())
  5. {
  6. client.newRequest("localhost", 8080)
  7. .content(content)
  8. .send(new Response.CompleteListener()
  9. {
  10. @Override
  11. public void onComplete(Result result)
  12. {
  13. // Your logic here
  14. }
  15. });
  16.  
  17. ...
  18.  
  19. // Write content
  20. writeContent(output);
  21. }
  22. // End of try-with-resource, output.close() called automatically to signal end of content

响应内容处理

Jetty HTTP client同意应用使用多种方式处理响应内容。

第一种方式是缓存响应内容在内存中;使用堵塞API,在一个ContentResponse 中内容的最大缓存是2MiB。

假设你想控制响应内容的长度(比如限制到小于2MiB的默认值),那么你能用一个org.eclipse.jetty.client.util.FutureResponseListener:

  1. Request request = httpClient.newRequest("http://domain.com/path");
  2.  
  3. // Limit response content buffer to 512 KiB
  4. FutureResponseListener listener = new FutureResponseListener(request, 512 * 1024);
  5.  
  6. request.send(listener);
  7.  
  8. ContentResponse response = listener.get(5, TimeUnit.SECONDS);

假设响应内容长度逸出。响应想被终止,一个异常将被方法get()抛出。

假设你正在使用异步API。你能用BufferingResponseListener工具类:

  1. httpClient.newRequest("http://domain.com/path")
  2. // Buffer response content up to 8 MiB
  3. .send(new BufferingResponseListener(8 * 1024 * 1024)
  4. {
  5. @Override
  6. public void onComplete(Result result)
  7. {
  8. if (!result.isFailed())
  9. {
  10. byte[] responseContent = getContent();
  11. // Your logic here
  12. }
  13. }
  14. });

另外一种方法最有效率(由于它避免了内容拷贝),并同意你指定一个Response.ContentListener,或者一个子类。处理到达的内容:

  1. ContentResponse response = httpClient
  2. .newRequest("http://domain.com/path")
  3. .send(new Response.Listener.Empty()
  4. {
  5. @Override
  6. public void onContent(Response response, ByteBuffer buffer)
  7. {
  8. // Your logic here
  9. }
  10. });

第三种方法同意你等待响应,然后用InputStreamResponseListener工具类输出内容:

  1. InputStreamResponseListener listener = new InputStreamResponseListener();
  2. httpClient.newRequest("http://domain.com/path")
  3. .send(listener);
  4.  
  5. // Wait for the response headers to arrive
  6. Response response = listener.get(5, TimeUnit.SECONDS);
  7.  
  8. // Look at the response
  9. if (response.getStatus() == 200)
  10. {
  11. // Use try-with-resources to close input stream.
  12. try (InputStream responseContent = listener.getInputStream())
  13. {
  14. // Your logic here
  15. }
  16. }

其他特征

Cookies支持

Jetty HTTP client原生的支持cookie。

HttpClient实例从HTTP响应收到cookie。然后存储他们在java.net.CookieStore中,这个类属于JDK。当新请求被创建,cookie缓存被查阅,假设存在匹配的cookie(即,coolie没有逸出。且匹配域和请求路径),这些cookie将被加入到请求。

应用能通过编程进入cookie缓存。查找设置的cookie:

  1. CookieStore cookieStore = httpClient.getCookieStore();
  2. List<HttpCookie> cookies = cookieStore.get(URI.create(<a target=_blank href="http://domain.com/path">http://domain.com/path</a>));

应用也能通过编程设置cookie,假设他们从一个HTTP响应返回:

  1. CookieStore cookieStore = httpClient.getCookieStore();
  2. HttpCookie cookie = new HttpCookie("foo", "bar");
  3. cookie.setDomain("domain.com");
  4. cookie.setPath("/");
  5. cookie.setMaxAge(TimeUnit.DAYS.toSeconds(1));
  6. cookieStore.add(URI.create("http://domain.com"), cookie);

你能移除不想再使用的cookies:

  1. CookieStore cookieStore = httpClient.getCookieStore();
  2. URI uri = URI.create("http://domain.com");
  3. List<HttpCookie> cookies = cookieStore.get(uri);
  4. for (HttpCookie cookie : cookies)
  5. cookieStore.remove(uri, cookie);

假设你想全然地禁用cookie处理,你能安装一个HttpCookieStore.Empty实例:

  1. httpClient.setCookieStore(new HttpCookieStore.Empty());

你能激活cookie过滤,通过安装一个履行过滤逻辑的cookie缓存:

  1. httpClient.setCookieStore(new GoogleOnlyCookieStore());
  2.  
  3. public class GoogleOnlyCookieStore extends HttpCookieStore
  4. {
  5. @Override
  6. public void add(URI uri, HttpCookie cookie)
  7. {
  8. if (uri.getHost().endsWith("google.com"))
  9. super.add(uri, cookie);
  10. }
  11. }

上面的样例将仅保留来自google.com域或者子域的cookies。

认证支持

Jetty HTTP client支持"Basic"和"Digest"认证机制,在RFC 2617中定义。

你能在HTTP client实例中配置认证证书例如以下:

  1. URI uri = new URI("http://domain.com/secure");
  2. String realm = "MyRealm";
  3. String user = "username";
  4. String pass = "password";
  5.  
  6. // Add authentication credentials
  7. AuthenticationStore auth = httpClient.getAuthenticationStore();
  8. auth.addAuthentication(new BasicAuthentication(uri, realm, user, pass));
  9.  
  10. ContentResponse response = httpClient
  11. .newRequest(uri)
  12. .send()
  13. .get(5, TimeUnit.SECONDS);

成功的认证被缓存,可是你能清除它们,迫使又一次认证:

  1. httpClient.getAuthenticationStore().clearAuthenticationResults();

代理支持

Jetty的HTTP client能被配置使用代理。

两种类型的代理是原生的支持的:HTTP代理(通过类org.eclipse.jetty.client.HttpProxy提供)和SOCKS 4代理(通过类org.eclipse.jetty.client.Socks4Proxy提供)。其他实现能够通过子类ProxyConfiguration.Proxy来写。

一个典型的配置例如以下:

  1. ProxyConfiguration proxyConfig = httpClient.getProxyConfiguration();
  2. HttpProxy proxy = new HttpProxy("proxyHost", proxyPort);
  3. // Do not proxy requests for localhost:8080
  4. proxy.getExcludedAddresses().add("localhost:8080");
  5.  
  6. httpClient.setProxyConfiguration(proxyConfig);
  7.  
  8. ContentResponse response = httpClient.GET(uri);

你指定代理的主机和port。也设置你不想被代理的地址,然后在HttpClient实例上设置代理配置。

Jetty开发指导:HTTP Client的更多相关文章

  1. Jetty开发指导:Jetty Websocket API

    Jetty WebSocket API使用 Jetty提供了功能更强的WebSocket API,使用一个公共的核心API供WebSockets的服务端和client使用. 他是一个基于WebSock ...

  2. Jetty开发指导:WebSocket介绍

    WebSocket是一个新的基于HTTP的双向通讯的协议. 它是基于低级别的框架协议.使用UTF-8 TEXT或者BINARY格式传递信息. 在WebSocket中的单个信息能够是不论什么长度(然而底 ...

  3. Jetty开发指导:框架

    Spring设置 你能嵌入Jetty到你的项目中,也能够使用差点儿全部的IoC类型框架,包含Spring.假设全部你想做的是在你的Spring中设置Jetty Server,那么以下的xml片段能够作 ...

  4. Jetty使用教程(四:21-22)—Jetty开发指南

    二十一.嵌入式开发 21.1 Jetty嵌入式开发HelloWorld 本章节将提供一些教程,通过Jetty API快速开发嵌入式代码 21.1.1 下载Jetty的jar包 Jetty目前已经把所有 ...

  5. IntelliJ IDEA: maven & jetty 开发 java web

    之前使用eclipse + maven + jetty开发java web应用,本着no zuo no gain的想法, 折腾了一下Intellj idea下开发环境的搭建,顺带学习了maven re ...

  6. eclipse集成jetty开发web项目(不采用maven方式)

    以前开发过程部署项目都是采用tomcat,偶然发现jetty,所以试了下,挺方便的,直切主题. 1.下载jetty,楼主使用的jetty8,地址http://download.eclipse.org/ ...

  7. Jetty 开发指南: 嵌入式开发之HelloWorld

    Jetty 嵌入式之 HelloWorld 本节提供一个教程,演示如何快速开发针对Jetty API的嵌入式代码. 1. 下载 Jar 包 Jetty被分解为许多jar和依赖项,通过选择最小的jar集 ...

  8. Jetty 开发指南:Jetty 内嵌开发

    Jetty的口号是“不要在Jetty中部署你的应用程序,在你的应用程序中部署Jetty!” 这意味着,作为将应用程序捆绑为要部署在Jetty中的标准WAR的替代方案,Jetty旨在成为一个软件组件,可 ...

  9. 乘风破浪,Windows11设计和开发指导,全新图标字体和云母材质

    Windows11全新的布局设计 Windows 11全新的布局设计已设计为支持现代应用体验.渐进的圆角.嵌套元素和一致的排水沟相结合,营造出柔和.平静.平易近人的效果,强调目的的统一和易用性. ht ...

随机推荐

  1. Nginx的500,502,504错误解决方法

    Nginx的500,502,504错误解决方法 一.解决500错误: 1.500错误指的是服务器内部错误,也就是服务器遇到意外情况,而无法履行请求. 2.500错误一般有几种情况: (1)web脚本错 ...

  2. Git 将本次修改追加在上一次修改上面

    Git 将本次修改追加在上一次修改上面 git add . git commit --amend 之后就是进入日志提交页面 确保change-Id那条记录出现在最后一行,如: zh-->en 修 ...

  3. UIView详解1

    一个UIView的实例就是一个视图,表示的是屏幕上的一块矩形区域,负责这块矩形区域的描绘以及和用户的交互. 第一.UIView的可视化属性 1. backgroundColor  背景属性 2. hi ...

  4. CSS:重量和级联规则,确定其优先级

    资源:http://www.ido321.com/1063.html 首先,给大家看一篇关于CSS优先级的演示样例:http://www.ido321.com/76.html 一.主要的优先级规则 比 ...

  5. 在VS中实现webService的一个demo(图解)

    在VS中实现webService的一个demo(图解) 先创建一个web项目,创建好web项目后,添加新建项——web服务 在新建好的web服务文件中写如下代码: 生成当前解决方案. 新建一个winf ...

  6. Linux下安装配置词典GoldenDict

    GoldenDict   apt-get install goldendict 安装完成以后,需要自己手动加入字典,增加在线翻译网址(例如,有道,金山等),点击 编辑--dictionaries  完 ...

  7. perl malformed JSON string, neither tag, array, object, number, string or atom, at character offset

    [root@wx03 ~]# cat a17.pl use JSON qw/encode_json decode_json/ ; use Encode; my $data = [ { 'name' = ...

  8. 获取DOM元素位置和尺寸大小

    JavaScript获取DOM元素位置和尺寸大小 在一些复杂的页面中经常会用JavaScript处理一些DOM元素的动态效果,这种时候我们经常会用到一些元素位置和尺寸的计算,浏览器兼容性问题也是不可忽 ...

  9. POJ 2404 Jogging Trails

    Jogging Trails Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2122   Accepted: 849 Des ...

  10. EasyUI DataGrid 中字段 formatter 格式化不起作用

    今天用 EasyUI datagrid 来做列表,要对一些数据进行格式化,推断某字段状态时,发现 formatter 格式化相应的函数不起作用. <table id="list_dat ...