如何与okhttp 离线缓存使用缓存中的数据时,离线改造

本资源由最后更新。
http是现在主流应用使用的网络请求方式, 用来交换数据和内容, 有效的使用HTTP可以使你的APP 变的更快和减少流量的使用
OkHttp 是一个很棒HTTP客户端:
支持SPDY, 可以合并多个到同一个主机的请求
使用连接池技术减少请求的延迟(如果SPDY是可用的话)
使用GZIP压缩减少传输的数据量
缓存响应避免重复的网络请求
当你的网络出现拥挤的时候,就是OKHttp 大显身手的时候, 它可以避免常见的网络问题,如果你的服务是部署在不同的IP上面的,如果第一个连接失败, OkHTtp会尝试其他的连接. 这个对现在IPv4+IPv6 中常见的把服务冗余部署在不同的数据中心上.
OkHttp 将使用现在TLS特性(SNI ALPN) 来初始化新的连接. 如果握手失败, 将切换到SLLv3
使用OkHttp很容易,
同时支持 异步阻塞请求和回调.
如果你使用OkHttp ,你不用重写你的代码,
okhttp-urlconnection模块实现了 java.net.HttpURLConnection 中的API,
okhttp-apache模块实现了HttpClient中的API
请求一个URL
这里例子请求一个URL,并以字符串的格式打印内容,全部代码参考这里
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
Response response = client.newCall(request).execute();
return response.body().string();
12345678910
OkHttpClient client = new OkHttpClient();&String run(String url) throws IOException {&&Request request = new Request.Builder()&&&&&&.url(url)&&&&&&.build();&&&Response response = client.newCall(request).execute();&&return response.body().string();}
向服务器POST请求
向服务器发送POST请求,全部代码参照这里 .
public static final MediaType JSON
= MediaType.parse("application/ charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.post(body)
Response response = client.newCall(request).execute();
return response.body().string();
1234567891011121314
public static final MediaType JSON&&&&= MediaType.parse("application/ charset=utf-8");&OkHttpClient client = new OkHttpClient();&String post(String url, String json) throws IOException {&&RequestBody body = RequestBody.create(JSON, json);&&Request request = new Request.Builder()&&&&&&.url(url)&&&&&&.post(body)&&&&&&.build();&&Response response = client.newCall(request).execute();&&return response.body().string();}
你还需要下载 ,
OKhttp使用这个库用来快速的I/O处理 在这里下载 .
Maven方式下载
&dependency&
&groupId&com.squareup.okhttp&/groupId&
&artifactId&okhttp&/artifactId&
&version&(insert latest version)&/version&
&/dependency&
&dependency&&&&groupId&com.squareup.okhttp&/groupId&&&&artifactId&okhttp&/artifactId&&&&version&(insert latest version)&/version&&/dependency&
compile 'com.squareup.okhttp:okhttp:2.0.0'
compile 'com.squareup.okhttp:okhttp:2.0.0'
MockWebServer
一种用于测试HTTP ,HTTPS和HTTP / 2客户端库。
MockWebServer与OkHttp耦合是HTTP / 2,这样的代码可以共享适当的测试是必不可少的。
下载 或者通过 Maven:
&dependency&
&groupId&com.squareup.okhttp3&/groupId&
&artifactId&mockwebserver&/artifactId&
&version&3.4.1&/version&
&scope&test&/scope&
&/dependency&
&dependency&&&&groupId&com.squareup.okhttp3&/groupId&&&&artifactId&mockwebserver&/artifactId&&&&version&3.4.1&/version&&&&scope&test&/scope&&/dependency&
或者 Gradle:
testCompile 'com.squareup.okhttp3:mockwebserver:3.4.1'
testCompile 'com.squareup.okhttp3:mockwebserver:3.4.1'
Apache OpenNLP遵循发布。
资源整理者简介:
可能感兴趣的文章
按分类快速查找
关于资源导航
伯乐在线资源导航收录优秀的工具资源。内容覆盖开发、设计、产品和管理等IT互联网行业相关的领域。目前已经收录 1378 项工具资源。
关于资源导航
伯乐在线资源导航收录优秀的工具资源。内容覆盖开发、设计、产品和管理等IT互联网行业相关的领域。
新浪微博:
推荐微信号
(加好友请注明来意)
- 好的话题、有启发的回复、值得信赖的圈子
- 分享和发现有价值的内容与观点
- 为IT单身男女服务的征婚传播平台
- 优秀的工具资源导航
- 翻译传播优秀的外文文章
- 国内外的精选博客文章
- UI,网页,交互和用户体验
- 专注iOS技术分享
- 专注Android技术分享
- JavaScript, HTML5, CSS
- 专注Java技术分享
- 专注Python技术分享
& 2016 伯乐在线Android的HTTP扩展包OkHttp中的缓存功能使用方法解析
作者:总李写代码
字体:[ ] 类型:转载 时间:
OkHttp(GitHub主页/square/okhttp)是一款高人气的第三方Android网络编程包,这里我们来看一下Android的HTTP扩展包OkHttp中的缓存功能使用方法解析:
OkHttp 可以对 HTTP 响应的内容在磁盘上进行缓存。在进行 HTTP 请求时,如果该请求的响应已经被缓存而且没有过期,OkHttp 会直接使用缓存中的响应内容,而不需要真正的发出 HTTP 请求到远程服务器。在创建缓存时需要指定一个磁盘目录和缓存的大小。在代码清单 8 中,创建出 Cache 对象之后,通过 OkHttpClient 的 setCache 进行设置。通过 Response 对象的 cacheResponse 和 networkResponse 方法可以得到缓存的响应和从实际的 HTTP 请求得到的响应。如果该请求的响应来自实际的网络请求,则 cacheResponse 方法的返回值为 null;如果响应来自缓存,则 networkResponse 的返回值为 null。OkHttp 在进行缓存时会遵循 HTTP 协议的要求,因此可以通过标准的 HTTP 头 Cache-Control 来控制响应的缓存时间。
设置响应缓存的示例
public class CacheResponse {
public static void main(String[] args) throws IOException {
int cacheSize = 100 * 1024 * 1024;
File cacheDirectory = Files.createTempDirectory("cache").toFile();
Cache cache = new Cache(cacheDirectory, cacheSize);
OkHttpClient client = new OkHttpClient();
client.setCache(cache);
Request request = new Request.Builder()
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException("服务器端错误: " + response);
System.out.println(response.cacheResponse());
System.out.println(response.networkResponse());
Cache-Control
Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令有下几种:
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
(1)no-cache指示请求或响应消息不能缓存
(2)no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
(3)max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
(4)min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
(5)max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
CacheControl类详细介绍:
1.)常用的函数:如下代码,里面已经加了注释就不一一解释了,每个函数都是对应一个缓存指令设置
&&&&&&&&&&
final CacheControl.Builder builder = new CacheControl.Builder();
builder.noCache();//不使用缓存,全部走网络
builder.noStore();//不使用缓存,也不存储缓存
builder.onlyIfCached();//只使用缓存
builder.noTransform();//禁止转码
builder.maxAge(10, TimeUnit.MILLISECONDS);//指示客户机可以接收生存期不大于指定时间的响应。
builder.maxStale(10, TimeUnit.SECONDS);//指示客户机可以接收超出超时期间的响应消息
builder.minFresh(10, TimeUnit.SECONDS);//指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
CacheControl cache = builder.build();//cacheControl
2.)两个CacheControl常量介绍:
CacheControl.FORCE_CACHE; //仅仅使用缓存
CacheControl.FORCE_NETWORK;// 仅仅使用网络
举例,我们设置一个有效期为10秒的CacheControl
final CacheControl.Builder builder = new CacheControl.Builder();
builder.maxAge(10, TimeUnit.MILLISECONDS);
CacheControl cache = builder.build();
3.)请求时如何使用
final CacheControl.Builder builder = new CacheControl.Builder();
builder.maxAge(10, TimeUnit.MILLISECONDS);
CacheControl cache = builder.build();
final Request request = new Request.Builder().cacheControl(cache).url(requestUrl).build();
final Call call = mOkHttpClient.newCall(request);//
call.enqueue(new Callback() {
public void onFailure(Call call, IOException e) {
failedCallBack("访问失败", callBack);
Log.e(TAG, e.toString());
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String string = response.body().string();
Log.e(TAG, "response -----&" + string);
successCallBack((T) string, callBack);
failedCallBack("服务器错误", callBack);
} catch (Exception e) {
Log.e(TAG, e.toString());
以上如果cache没有过去会直接返回cache而不会发起网络请求,若过期会自动发起网络请求。注意:如果您使用FORCE_CACHE和网络的响应需求,OkHttp则会返回一个504提示,告诉你不可满足请求响应。所以我们加一个判断在没有网络的情况下使用
//判断网络是否连接
boolean connected = NetworkUtil.isConnected(context);
if (!connected) {
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具Okhttp的高效使用方式 - 博客频道 - CSDN.NET
robert的专栏
Android开发,java编程
分类:android
&OkHttp 是一个很重要的开源库。它的默认配置已经提供了很好的效果,我们还是采取了一些措施提高 OkHttp 的可用性和自我检查能力:
1. 在文件系统中开启响应缓存
有些响应消息通过包含Cache-Control HTTP首部字段允许缓存,但是默认情况下,OkHttp 并不会缓存这些响应消息。因此你的客户端可能会因为不断请求相同的资源而浪费时间和带宽,而不是简单地读取一下首次响应消息的缓存副本。
为了在文件系统中开启响应缓存,需要配置一个 com.squareup.okhttp.Cache 实例,然后把它传递 给 OkHttpClient 实例的 setCache 方法。你必须用一个表示目录的 File 对象和最大字节数来实例化 Cache 对象。那些 能够缓存的响应消息会被写在指定的目录中。如果已缓存的响应消息导致目录内容超过了指定的大小,响应消息会按照最近最少使用( LRU Policy )的策略被移除。
正如 Jesse Wilson 所建议的 ,我们将响应消息缓存在 context.getCacheDir() 的子文件夹中:
final @Nullable File baseDir = context.getCacheDir();
if (baseDir != null) {
& final File cacheDir = new File(baseDir, &HttpResponseCache&);
& okHttpClient.setCache(new Cache(cacheDir, 10*));
2. 集成 Stetho
Stetho 是一个 Facebook 出品的超赞的开源库,它可以让你用 Chrome 的功能—— 开发者工具 来检查调试Android 应用。
Stetho 不仅能够检查应用的 SQLite 数据库和视图层次,还可以检查 OkHttp 的每一条请求和响应消息:
这种自我检查方式(Introspection)有效地确保了服务器返回允许缓存资源的 HTTP 首部时,且核缓存资源存在时,不再发出任何请求。
开启 Stetho,
public class MyApplication extends Application {
& public void onCreate() {
&&& super.onCreate();
&&& Stetho.initializeWithDefaults(this);
添加一个 StethoInterceptor 实例到网络拦截器(Network Interceptor)的列表中去:
OkHttpClient client = new OkHttpClient();
client.networkInterceptors().add(new StethoInterceptor());
new OkHttpClient.Builder()
&&& .addNetworkInterceptor(new StethoInterceptor())
&&& .build();
应用运行完毕之后,打开 Chrome 然后跳转到 chrome://inspect。设备、应用以及应用标识符信息会被陈列出来。直接点击“inspect”链接就可以打开开发者工具,然后切换到 Network 标签开始监测 OkHttp 发出的请求。
3. 使用 Picasso 和 Retrofit
可能和我们一样,你使用 Picasso 来加载网络图片,或者使用& Retrofit 来简化网络请求和解析响应消息。在默认情况下,如果你没有显式地指定一个 OkHttpClient,这些开源库会隐式地创建它们自己 的 OkHttpClient 实例以供内部使用。以下代码来自于 Picasso 2.5.2 版本的OkHttpDownloader 类:
private static OkHttpClient defaultOkHttpClient() {
& OkHttpClient client = new OkHttpClient();
& client.setConnectTimeout(Utils.DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
& client.setReadTimeout(Utils.DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
& client.setWriteTimeout(Utils.DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
Retrofit 也有类似的工厂方法用来创建它自己的 OkHttpClient,在OkClient类中。
图片是应用中需要加载的最大的资源之一。Picasso 是严格地按照 LRU 策略在内存中维护它的图片缓存。如果客户端尝试用 Picasso 加载一张图片,并且 Picasso 没有在内存缓存中找到该图片,那么它会委托内部的 OkHttpClient 实例来加载该图片。在默认情况下,由于前面的 defaultOkHttpClient 方法没有在文件系统中配置响应缓存,该实例会一直从服务器加载图片。
自定义一个 OkHttpClient 实例,将从文件系统返回一个已缓存的响应消息这种情况考虑在内。没有一张图片直接从服务器加载。这在应用第一次加载时是尤为重要的。在这个时候,Picasso 的内存中的缓存是 “冷” 的,它会频繁地委托 OkHttpClient 实例去加载图片。
这就需要构建一个用你的 OkHttpClient 配置的 Picasso 实例。如果你在代码中使用 Picasso.with(context).load(...) 来加载图片,你所使用的 Picasso 单例对象,是在with 方法中用自己 的 OkHttpClient 延迟加载和配置的。因此我们必须在第一次调用 with方法之前指定自己的 Picasso 实例作为单例对象。
简单地把 OkHttpClient 实例包装到一个 OkHttpDownloader 对象中,然后传递给Picasso.Builder 实例的 downloader 方法:
final Picasso picasso = new Picasso.Builder(context)
&&& .downloader(new OkHttpDownloader(okHttpClient))
&&& .build();
//客户端应该在任何需要的时候来创建这个实例
//以防万一,替换掉那个单例对象
Picasso.setSingletonInstance(picasso);
在 Retrofit 1.9.x 中,通过 RestAdapter 使用你的 OkHttpClient 实例,把 OkHttpClient实例包装到一个 OkClient 实例 中,然后传递给 RestAdapter.Builder 实例的 setClient方法:
restAdapterBuilder.setClient(new OkClient(httpClient));
在 Retrofit 2.0 中,直接把 OkHttpClient 实例传递给 Retrofit.Builder 实例的 client即可。
4. 设置用户代理拦截器(User-Agent Interceptor)
当客户端在每一次请求中都提供一个详细的 User-Agent 头部信息时,日志文件和分析数据提供了很有用的信息。默认情况下,OkHttp 的 User-Agent 值仅仅只有它的版本号。要设定你自己的 User-Agent,创建一个拦截器(Interceptor)然后替换掉默认值,参考 StackOverflow 上的建议 :
public final class UserAgentInterceptor implements Interceptor {
& private static final String USER_AGENT_HEADER_NAME = &User-Agent&;
& private final String userAgentHeaderV
& public UserAgentInterceptor(String userAgentHeaderValue) {
&&& this.userAgentHeaderValue = Preconditions.checkNotNull(userAgentHeaderValue);
& @Override
& public Response intercept(Chain chain) throws IOException {
&&& final Request originalRequest = chain.request();
&&& final Request requestWithUserAgent = originalRequest.newBuilder()
&&&&&&& .removeHeader(USER_AGENT_HEADER_NAME)
&&&&&&& .addHeader(USER_AGENT_HEADER_NAME, userAgentHeaderValue)
&&&&&&& .build();
&&& return chain.proceed(requestWithUserAgent);
使用任何你觉得有价值的信息,来创建 User-Agent。
如果你的应用中用到了 WebView,你可以配置使用相同的 User-Agent 值,即之前创建的 UserAgentInterceptor:
WebSettings settings = webView.getSettings();
settings.setUserAgentString(userAgentHeaderValue);
5. 指定合理的超时
在 2.5.0 版本之前,OkHttp 请求默认永不超时。从 2.5.0 版本开始,如果建立了一个连接,或从连接读取下一个字节,或者向连接写入下一个字节,用时超过了10秒,请求就会超时。分别调 用 setConnectTimeout,setReadTimeout 或 setWriteTimeout 方法可以重写那些默认值。
Picasso 和 Retrofit 为它们的默认 OkHttpClient 实例指定不同的超时时长。 默认情况下, Picasso 设定如下:
- 连接超时15秒
- 读取超时20秒
- 写入超时20秒
Retrofit 设定如下:
- 连接超时15秒
- 读取超时20秒
- 写入无超时
用你自己的 OkHttpClient 实例配置好 Picasso 和 Retrofit 之后,就能确保所有请求超时的一致性了。
扫码关注公众账号,分享更多资料。
排名:第5101名
我的微信公共账号
关注我的微信公众号,第一时间获得博客的更新提醒,更有很多其它的技术信息分享给大家,扫一扫下方二维码或搜索微信号le_coding即可关注
(5)(26)(12)(73)(18)developerWorks 社区
在 Java 平台上,我们一般使用 Apache HttpClient 作为通常的 HTTP 客户端。Square 公司开源的 OkHttp 是一个更先进的专注于连接效率的 HTTP 客户端。OkHttp 提供了对 HTTP/2 和 SPDY 的支持,并提供了连接池,GZIP 压缩和 HTTP 响应缓存功能。OkHttp 的 API 接口也更加的简单实用。可以将 OkHttp 作为 Apache HttpClient 的升级与替换,本文将对其进行详细的介绍。
, 软件工程师
成富,毕业于北京大学,获得计算机软件与理论专业硕士学位,曾经在 developerWorks 和 InfoQ 中文站上发表多篇技术文章。著有《深入理解 Java 7:核心技术与最佳实践》一书。个人网站是 。
在 Java 程序中经常需要用到 HTTP 客户端来发送 HTTP 请求并对所得到的响应进行处理。比如屏幕抓取(screen
scraping)程序通过 HTTP 客户端来访问网站并解析所得到的 HTTP 文档。在 Java 服务端程序中也可能需要使用 HTTP 客户端来与第三方 REST 服务进行集成。随着微服务(microservices)的流行,HTTP 成为不同服务之间的标准集成方式。HTTP 客户端的重要性也日益显著。在 Java 平台上,Java 标准库提供了 HttpURLConnection 类来支持 HTTP 通讯。不过 HttpURLConnection 本身的 API 不够友好,所提供的功能也有限。大部分 Java 程序都选择使用 Apache 的开源项目 HttpClient 作为 HTTP 客户端。Apache
HttpClient 库的功能强大,使用率也很高,基本上是 Java 平台中事实上的标准 HTTP 客户端。本文介绍的是由 Square 公司开发的 OkHttp,是一个专注于性能和易用性的 HTTP 客户端。OkHttp 简介OkHttp 库的设计和实现的首要目标是高效。这也是选择 OkHttp 的重要理由之一。OkHttp 提供了对最新的 HTTP 协议版本 HTTP/2 和 SPDY 的支持,这使得对同一个主机发出的所有请求都可以共享相同的套接字连接。如果 HTTP/2 和 SPDY 不可用,OkHttp 会使用连接池来复用连接以提高效率。OkHttp 提供了对 GZIP 的默认支持来降低传输内容的大小。OkHttp 也提供了对 HTTP 响应的缓存机制,可以避免不必要的网络请求。当网络出现问题时,OkHttp 会自动重试一个主机的多个 IP 地址。在 Java 程序中使用 OkHttp 非常简单,只需要在 Maven 的 POM 文件中添加 中的依赖即可。目前 OkHttp 的最新版本是 2.5.0。清单 1.
OkHttp 的 Maven 依赖声明&dependency&
 &groupId&com.squareup.okhttp&/groupId&
 &artifactId&okhttp&/artifactId&
 &version&2.5.0&/version&
&/dependency&HTTP 连接虽然在使用 OkHttp 发送 HTTP 请求时只需要提供 URL 即可,OkHttp 在实现中需要综合考虑 3 种不同的要素来确定与 HTTP 服务器之间实际建立的 HTTP 连接。这样做的目的是为了达到最佳的性能。首先第一个考虑的要素是 URL 本身。URL 给出了要访问的资源的路径。比如 URL
所对应的是百度首页的 HTTP 文档。在 URL 中比较重要的部分是访问时使用的模式,即 HTTP 还是 HTTPS。这会确定 OkHttp 所建立的是明文的 HTTP 连接,还是加密的 HTTPS 连接。第二个要素是 HTTP 服务器的地址,如 。每个地址都有对应的配置,包括端口号,HTTPS 连接设置和网络传输协议。同一个地址上的 URL 可以共享同一个底层 TCP 套接字连接。通过共享连接可以有显著的性能提升。OkHttp 提供了一个连接池来复用连接。第三个要素是连接 HTTP 服务器时使用的路由。路由包括具体连接的 IP 地址(通过 DNS 查询来发现)和所使用的代理服务器。对于 HTTPS 连接还包括通讯协商时使用的 TLS 版本。对于同一个地址,可能有多个不同的路由。OkHttp 在遇到访问错误时会自动尝试备选路由。当通过 OkHttp 来请求某个 URL 时,OkHttp 首先从 URL 中得到地址信息,再从连接池中根据地址来获取连接。如果在连接池中没有找到连接,则选择一个路由来尝试连接。尝试连接需要通过 DNS 查询来得到服务器的 IP 地址,也会用到代理服务器和 TLS 版本等信息。当实际的连接建立之后,OkHttp 发送 HTTP 请求并获取响应。当连接出现问题时,OkHttp 会自动选择另外的路由进行尝试。这使得 OkHttp 可以自动处理可能出现的网络问题。当成功获取到 HTTP 请求的响应之后,当前的连接会被放回到连接池中,提供给后续的请求来复用。连接池会定期把闲置的连接关闭以释放资源。请求,响应与调用HTTP 客户端所要执行的任务很简单,接受 HTTP 请求并返回响应。每个 HTTP 请求包括 URL,HTTP 方法(如 GET 或 POST),HTTP 头和请求的主体内容等。HTTP 请求的响应则包含状态代码(如 200 或 500),HTTP 头和响应的主体内容等。虽然请求和响应的交互模式很简单,但在实现中仍然有很多细节要考虑。OkHttp 会对收到的请求进行一定的处理,比如增加额外的 HTTP 头。同样的,OkHttp 也可能在返回响应之前对响应做一些处理。例如,OkHttp 可以启用 GZIP 支持。在发送实际的请求时,OkHttp 会加上 HTTP 头 Accept-Encoding。在接收到服务器的响应之后,OkHttp 会先做解压缩处理,再把结果返回。如果 HTTP 响应的状态代码是重定向相关的,OkHttp 会自动重定向到指定的 URL 来进一步处理。OkHttp 也会处理用户认证相关的响应。OkHttp 使用调用(Call)来对发送 HTTP 请求和获取响应的过程进行抽象。 中给出了使用 OkHttp 发送 HTTP 请求的基本示例。首先创建一个 OkHttpClient 类的对象,该对象是使用 OkHttp 的入口。接着要创建的是表示 HTTP 请求的 Request 对象。通过 Request.Builder 这个构建帮助类可以快速的创建出 Request 对象。这里指定了 Request 的 url 为 。接着通过 OkHttpClient 的 newCall 方法来从 Request 对象中创建一个 Call 对象,再调用 execute 方法来执行该调用,所得到的结果是表示 HTTP 响应的 Response 对象。通过 Response 对象中的不同方法可以访问响应的不同内容。如 headers 方法来获取 HTTP 头,body 方法来获取到表示响应主体内容的 ResponseBody 对象。清单 2.
OkHttp 最基本的 HTTP 请求public class SyncGet {
   public static void main(String[] args) throws IOException {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
            .url("")
            .build();
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) {
        throw new IOException("服务器端错误: " + response);
    }
    Headers responseHeaders = response.headers();
    for (int i = 0; i & responseHeaders.size(); i++) {
        System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
    }
    System.out.println(response.body().string());
   }
}HTTP 头处理HTTP 头是 HTTP 请求和响应中的重要组成部分。在创建 HTTP 请求时需要设置一些 HTTP 头。在得到 HTTP 的响应之后,也会需要对其中包含的 HTTP 头进行解析。从代码的角度来说,HTTP 头的数据结构是 Map&String,
List&String&&类型。也就是说,对于每个 HTTP 头,可能有多个值。但是大部分 HTTP 头都只有一个值,只有少部分 HTTP 头允许多个值。OkHttp 采用了简单的方式来区分这两种类型,使得对 HTTP 头的使用更加简单。在设置 HTTP 头时,使用 header(name,
value) 方法来设置 HTTP 头的唯一值。对同一个 HTTP 头,多次调用该方法会覆盖之前设置的值。使用 addHeader(name,
value) 方法来为 HTTP 头添加新的值。在读取 HTTP 头时,使用 header(name) 方法来读取 HTTP 头的最近出现的值。如果该 HTTP 头只有单个值,则返回该值;如果有多个值,则返回最后一个值。使用 headers(name) 方法来读取 HTTP 头的所有值。 中使用 header 方法设置了 User-Agent 头的值,并添加了一个 Accept 头的值。在进行解析时,通过 header 方法来获取 Server 头的单个值,通过 headers 方法来获取 Set-Cookie 头的所有值。清单 3.
HTTP 头设置和读取的示例public class Headers {
   public static void main(String[] args) throws IOException {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
            .url("")
            .header("User-Agent", "My super agent")
            .addHeader("Accept", "text/html")
            .build();
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) {
        throw new IOException("服务器端错误: " + response);
    }
    System.out.println(response.header("Server"));
    System.out.println(response.headers("Set-Cookie"));
   }
}POST 请求HTTP POST 和 PUT 请求可以包含要提交的内容。只需要在创建 Request 对象时,通过 post 和 put 方法来指定要提交的内容即可。 中通过 RequestBody 的 create 方法来创建媒体类型为 text/plain 的内容并提交。清单 4. HTTP
POST 请求的基本示例public class PostString {
   public static void main(String[] args) throws IOException {
    OkHttpClient client = new OkHttpClient();
    MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
    String postBody = "Hello World";
    Request request = new Request.Builder()
            .url("")
            .post(RequestBody.create(MEDIA_TYPE_TEXT, postBody))
            .build();
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) {
        throw new IOException("服务器端错误: " + response);
    }
    System.out.println(response.body().string());
   }
}以 String 类型提交内容只适用于内容比较小的情况。当请求内容较大时,应该使用流来提交。 中给了使用流方式来提交内容的示例。这里创建了 RequestBody 的一个匿名子类。该子类的 contentType 方法需要返回内容的媒体类型,而 writeTo 方法的参数是一个 BufferedSink 对象。我们需要做的就是把请求的内容写入到 BufferedSink 对象即可。清单 5.
使用流方法提交 HTTP POST 请求的示例public class PostStream {
   public static void main(String[] args) throws IOException {
    OkHttpClient client = new OkHttpClient();
    final MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
    final String postBody = "Hello World";
    RequestBody requestBody = new RequestBody() {
        @Override
        public MediaType contentType() {
            return MEDIA_TYPE_TEXT;
        }
        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            sink.writeUtf8(postBody);
        }
        public long contentLength() throws IOException {
            return postBody.length();
        }
    };
    Request request = new Request.Builder()
            .url("")
            .post(requestBody)
            .build();
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) {
        throw new IOException("服务器端错误: " + response);
    }
    System.out.println(response.body().string());
   }
}如果所要提交的内容来自本地文件,则不需要额外的流操作,只需要通过 RequestBody 的 create 方法,并把 File 类型的对象作为参数传入即可。如果需要模拟 HTML 中的表单提交,可以通过 FormEncodingBuilder 来创建请求内容,见。清单 6. 表单提交示例RequestBody formBody = new FormEncodingBuilder()
            .add("query", "Hello")
            .build();如果需要模拟 HTML 中的文件上传功能,可以通过 MultipartBuilder 来创建 multipart 请求内容。 中的 multipart 请求添加了一个表单属性 title 和一个文件 file。清单 7.
提交 multipart 请求的示例MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
RequestBody requestBody = new MultipartBuilder()
    .type(MultipartBuilder.FORM)
    .addPart(
            Headers.of("Content-Disposition", "form- name=\"title\""),
            RequestBody.create(null, "测试文档"))
    .addPart(
            Headers.of("Content-Disposition", "form- name=\"file\""),
            RequestBody.create(MEDIA_TYPE_TEXT, new File("input.txt")))
    .build();响应缓存OkHttp 可以对 HTTP 响应的内容在磁盘上进行缓存。在进行 HTTP 请求时,如果该请求的响应已经被缓存而且没有过期,OkHttp 会直接使用缓存中的响应内容,而不需要真正的发出 HTTP 请求到远程服务器。在创建缓存时需要指定一个磁盘目录和缓存的大小。在 中,创建出 Cache 对象之后,通过 OkHttpClient 的 setCache 进行设置。通过 Response 对象的 cacheResponse 和 networkResponse 方法可以得到缓存的响应和从实际的 HTTP 请求得到的响应。如果该请求的响应来自实际的网络请求,则 cacheResponse 方法的返回值为 null;如果响应来自缓存,则 networkResponse 的返回值为 null。OkHttp 在进行缓存时会遵循 HTTP 协议的要求,因此可以通过标准的 HTTP 头 Cache-Control 来控制响应的缓存时间。清单 8.
设置响应缓存的示例public class CacheResponse {
   public static void main(String[] args) throws IOException {
    int cacheSize = 100 * 1024 * 1024;
    File cacheDirectory = Files.createTempDirectory("cache").toFile();
    Cache cache = new Cache(cacheDirectory, cacheSize);
    OkHttpClient client = new OkHttpClient();
    client.setCache(cache);
    Request request = new Request.Builder()
            .url("")
            .build();
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) {
        throw new IOException("服务器端错误: " + response);
    }
    System.out.println(response.cacheResponse());
    System.out.println(response.networkResponse());
   }
}用户认证OkHttp 提供了对用户认证的支持。当 HTTP 响应的状态代码是 401 时,OkHttp 会从设置的 Authenticator 对象中获取到新的 Request 对象并再次尝试发出请求。Authenticator 接口中的 authenticate 方法用来提供进行认证的 Request 对象,authenticateProxy 方法用来提供对代理服务器进行认证的 Request 对象。 中新的 Request 对象中添加了 HTTP 基本认证的 Authorization 头。清单 9. 用户认证的示例OkHttpClient client = new OkHttpClient();
client.setAuthenticator(new Authenticator() {
public Request authenticate(Proxy proxy, Response response) throws IOException {
    String credential = Credentials.basic("user", "password");
    return response.request().newBuilder()
            .header("Authorization", credential)
            .build();
public Request authenticateProxy(Proxy proxy, Response response)
throws IOException {
   
});异步调用OkHttp 除了支持常用的同步 HTTP 请求之外,还支持异步 HTTP 请求调用。在使用同步调用时,当前线程会被阻塞,直到 HTTP 请求完成。当同时发出多个 HTTP 请求时,同步调用的性能会比较差。这个时候通过异步调用可以提高整体的性能。 给出了异步调用的示例。在通过 newCall 方法创建一个新的 Call 对象之后,不是通过 execute 方法来同步执行,而是通过 enqueue 方法来添加到执行队列中。在调用 enqueue 方法时需要提供一个 Callback 接口的实现。在 Callback 接口实现中,通过 onResponse 和 onFailure 方法来处理响应和进行错误处理。清单 10. 异步调用的示例public class AsyncGet {
   public static void main(String[] args) throws IOException {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
            .url("")
            .build();
    client.newCall(request).enqueue(new Callback() {
        public void onFailure(Request request, IOException e) {
            e.printStackTrace();
        }
        public void onResponse(Response response) throws IOException {
            if (!response.isSuccessful()) {
                throw new IOException("服务器端错误: " + response);
            }
            System.out.println(response.body().string());
        }
   }
}取消调用当一个 HTTP 调用执行之后,可以通过 Call 接口的 cancel 方法来取消该请求。当一个调用被取消之后,等待该请求的响应的代码会收到 IOException。同步和异步调用都可以被取消。如果需要同时取消多个请求,可以在创建请求时通过 RequestBuilder 的 tag 方法来为请求添加一个标签。在需要时可以通过 OkHttpClient 的 cancel 方法来取消拥有一个标签的所有请求。 中的所有请求都设置了标签 website,可以通过 cancel 方法来全部取消。清单 11.
取消 HTTP 请求的示例public class CancelRequest {
private OkHttpClient client = new OkHttpClient();
private String tag = "website";
public void sendAndCancel() {
    sendRequests(Lists.newArrayList(
            "",
            "",
            ".cn"));
    client.cancel(this.tag);
public void sendRequests(List&String& urls) {
    urls.forEach(url -& {
        client.newCall(new Request.Builder()
                    .url(url)
                    .tag(this.tag)
                    .build())
                .enqueue(new SimpleCallback());
    });
private static class SimpleCallback implements Callback {
    public void onFailure(Request request, IOException e) {
        e.printStackTrace();
    }
    public void onResponse(Response response) throws IOException {
        System.out.println(response.body().string());
    }
public static void main(String[] args) throws IOException {
    new CancelRequest().sendAndCancel();
}拦截器拦截器是 OkHttp 提供的对 HTTP 请求和响应进行统一处理的强大机制。拦截器在实现和使用上类似于 Servlet 规范中的过滤器。多个拦截器可以链接起来,形成一个链条。拦截器会按照在链条上的顺序依次执行。
拦截器在执行时,可以先对请求的 Request 对象进行修改;再得到响应的 Response 对象之后,可以进行修改之后再返回。 中的拦截器 LoggingInterceptor 用来记录 HTTP 请求和响应的相关信息。Interceptor 接口只包含一个方法 intercept,其参数是 Chain 对象。Chain 对象表示的是当前的拦截器链条。通过 Chain 的 request 方法可以获取到当前的 Request 对象。在使用完 Request 对象之后,通过 Chain 对象的 proceed 方法来继续拦截器链条的执行。当执行完成之后,可以对得到的 Response 对象进行额外的处理。清单 12.
记录请求和响应信息的拦截器public class LoggingInterceptor implements Interceptor {
public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    long t1 = System.nanoTime();
    System.out.println(String.format("发送请求: [%s] %s%n%s",
            request.url(), chain.connection(), request.headers()));
    Response response = chain.proceed(request);
    long t2 = System.nanoTime();
    System.out.println(String.format("接收响应: [%s] %.1fms%n%s",
            response.request().url(), (t2 - t1) / 1e6d, response.headers()));
   
}OkHttp 中的拦截器分成应用和网络拦截器两种。应用拦截器对于每个 HTTP 响应都只会调用一次,可以通过不调用 Chain.proceed 方法来终止请求,也可以通过多次调用 Chain.proceed 方法来进行重试。网络拦截器对于调用执行中的自动重定向和重试所产生的响应也会被调用,而如果响应来自缓存,则不会被调用。应用和网络拦截器的添加方式见。清单 13.
添加应用和网络拦截器client.interceptors().add(new LoggingInterceptor()); //添加应用拦截器
client.networkInterceptors().add(new LoggingInterceptor()); //添加网络拦截器小结OkHttp 作为一个简洁高效的 HTTP 客户端,可以在 Java 和 Android 程序中使用。相对于 Apache
HttpClient 来说,OkHttp 的性能更好,其 API 设计也更加简单实用。本文对 OkHttp 进行了详细的介绍,包括同步和异步调用、HTTP
GET 和 POST 请求处理、用户认证、响应缓存和拦截器等。对于新开发的 Java 应用,推荐使用 OkHttp 作为 HTTP 客户端。
下载描述名字大小示例代码25k
参考资料 参考 OkHttp 的,了解 OkHttp 的更多内容。了解更多
协议的内容。了解更多
协议的内容。了解更多
协议的内容。:这里有数百篇关于 Java 编程各个方面的文章。
加入 ,查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
免费下载、试用软件产品,构建应用并提升技能。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Java technology, Open sourceArticleID=1023472ArticleTitle=OkHttp:Java 平台上的新一代 HTTP 客户端publish-date=

我要回帖

更多关于 okhttp3 设置缓存 的文章

 

随机推荐