Cache-Control与retrofit缓存

深入理解Android缓存机制(三)磁盘缓存,十年Android编程开发生涯 Expires:当前客户端时间 + maxAge 。 而 Cache-Control:no-cache 和 Cache-Control:max-age=0 (单位是秒) 这里需要注意的是: Cache-Control 中指定的缓存过期策略优先级高于 Expires,当它们同时存在的时候,后者会被覆盖掉。 缓存数据标记为已过期只是告诉客户端不能再直接从本地读取缓存了,需要再发一次请求到服务器去确认,并不等同于本地缓存数据从此就没用了,有些情况下即使过期了还是会被再次用到,具体下面会讲到。 缓存对比策略 将 阅读详情

Cache-Control

HTTP中这个字段用于指定所有缓存机制在整个请求/响应链中必须服从的指令。缓存指令是单向的,即请求中存在一个指令并不意味着响应中将存在同一个指令。常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。

常用 cache-directive 值

Cache-directive

说明

public

所有内容都将被缓存(客户端和代理服务器都可缓存)

private

内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)

no-cache

必须先与服务器确认返回的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载。

no-store

所有内容都不会被缓存到缓存或 Internet 临时文件中

must-revalidation/proxy-revalidation

如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证

max-age=xxx (xxx is numeric)

缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高

Retrofit实现网络缓存

首先,配置OkHttp中Cache

OkHttpClient okHttpClient = new OkHttpClient();

File cacheFile = new File(context.getCacheDir(), "[缓存目录]");

Cache cache = new Cache(cacheFile, 1024 * 1024 * 100);//100Mb

okHttpClient.setCache(cache);


配置请求头中的Cache-Control

@FormUrlEncoded

    @Headers("Cache-Control: public,max-age:3600")

    @POST("?method=app.system.init")

    Observable<HttpResult<AppInit>>getAppInit(@Field("ucode") String ucode);

云端配合设置响应头或者自己写拦截器修改响应头response中cache-control

到这一步缓存就已经待在你的缓存目录了。
如果云端有处里cache的话,就已经可以了。
但是很可能云端没有处理,所以返回的响应头中cache-control是no-cache,这时候你还是无法做缓存,大家可以用okhttp的写日志拦截器查看响应头的内容。

如果云端现在不方便处理的话,你也可以自己搞定缓存的,那就是写拦截器修改响应头中的cache-control。

设置拦截器:

CacheControlInterceptor cacheControlInterceptor = newCacheControlInterceptor();

return new OkHttpClient

               .Builder()

               .addInterceptor(loggingInterceptor)

               .addInterceptor(paramsInterceptor)

                .addInterceptor(cacheInterceptor)

               .cache(cache)

               .build();

拦截器的代码如下:

public class CacheControlInterceptor implementsInterceptor {

 

    @Override

    public Responseintercept(Chain chain) throws IOException {

       CacheControl.Builder cacheBuilder = new CacheControl.Builder();

       cacheBuilder.maxAge(0, TimeUnit.SECONDS);

       cacheBuilder.maxStale(365, TimeUnit.DAYS);

       CacheControl cacheControl = cacheBuilder.build();

        Requestrequest = chain.request();

        if(!NetworkStateUtils.isNetworkAvailable()) {

            request= request.newBuilder()

                   .cacheControl(cacheControl)

                   .build();

        }

        ResponseoriginalResponse = chain.proceed(request);

        if(NetworkStateUtils.isNetworkAvailable()) {

            intmaxAge = 0; // read from cache

            returnoriginalResponse.newBuilder()

                   .removeHeader("Pragma")

                   .header("Cache-Control", "public ,max-age=" +maxAge)

                   .build();

        } else {

            intmaxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale

            returnoriginalResponse.newBuilder()

                   .removeHeader("Pragma")

                   .header("Cache-Control", "public, only-if-cached,max-stale=" + maxStale)

                   .build();

        }

    }

 

Retrofit支持缓存post请求

不过,因为Retrofit和OkHttp是以支持RestfulAPI为前提的,所以,只对get请求缓存。如果服务器不是标准的RestfulAPI,比如全部采用post请求,那么如何实现缓存呢?

Retrofit本身的缓存是通过DiskLRUCache实现的,我们可以仿照它来实现自己的缓存来支持post请求。

首先,引入DiskLRUCache

写一个工具类来设置和获取缓存:

public final class CacheManager {

 

    public staticfinal String TAG = "CacheManager";

 

    //max cachesize 100mb

    private static final long DISK_CACHE_SIZE =1024 * 1024 * 100;

 

    private staticfinal int DISK_CACHE_INDEX = 0;

 

    private staticfinal String CACHE_DIR = "responses";

    privatevolatile static CacheManager mCacheManager;

    privateDiskLruCache mDiskLruCache;

 

    privateCacheManager() {

        FilediskCacheDir = getDiskCacheDir(App.getContext(), CACHE_DIR);

        if(!diskCacheDir.exists()) {

            booleanb = diskCacheDir.mkdirs();

           Log.d(TAG, "!diskCacheDir.exists() --- diskCacheDir.mkdirs()="+ b);

        }

        if(diskCacheDir.getUsableSpace() > DISK_CACHE_SIZE) {

            try {

               mDiskLruCache = DiskLruCache.open(diskCacheDir,

                       getAppVersion(App.getContext()), 1/*一个key对应多少个文件*/, DISK_CACHE_SIZE);

               Log.d(TAG, "mDiskLruCache created");

            } catch(IOException e) {

               e.printStackTrace();

            }

        }

    }

 

    public staticCacheManager getInstance() {

        if (mCacheManager == null) {

           synchronized (CacheManager.class) {

                if(mCacheManager == null) {

                   mCacheManager = new CacheManager();

                }

            }

        }

        returnmCacheManager;

    }

 

    /**

     * 对字符串进行MD5编码

     */

    private staticString encryptMD5(String string) {

        try {

            byte[]hash = MessageDigest.getInstance("MD5").digest(

                   string.getBytes("UTF-8"));

           StringBuilder hex = new StringBuilder(hash.length * 2);

            for(byte b : hash) {

                if((b & 0xFF) < 0x10) {

                   hex.append("0");

                }

               hex.append(Integer.toHexString(b & 0xFF));

            }

            returnhex.toString();

        } catch(NoSuchAlgorithmException | UnsupportedEncodingException e) {

           e.printStackTrace();

        }

        returnstring;

    }

 

    /**

     * 同步设置缓存

     */

    public voidputCache(String key, String value) throws IOException {

        if(mDiskLruCache == null) return;

       OutputStream os = null;

        try {

           DiskLruCache.Editor editor = mDiskLruCache.edit(encryptMD5(key));

            os = editor.newOutputStream(DISK_CACHE_INDEX);

           os.write(value.getBytes());

           os.flush();

           editor.commit();

           mDiskLruCache.flush();

        } catch(IOException e) {

            throwe;

        } finally {

            if (os != null) {

                try{

                   os.close();

                }catch (IOException e) {

                   e.printStackTrace();

                }

            }

        }

    }

 

    /**

     * 同步获取缓存

     */

    public StringgetCache(String key) throws IOException {

        if(mDiskLruCache == null) {

            returnnull;

        }

       FileInputStream fis = null;

       ByteArrayOutputStream bos = null;

        try {

           DiskLruCache.Snapshot snapshot = mDiskLruCache.get(encryptMD5(key));

            if(snapshot != null) {

                fis= (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);

                bos= new ByteArrayOutputStream();

               byte[] buf = new byte[1024];

                intlen;

               while ((len = fis.read(buf)) != -1) {

                   bos.write(buf, 0, len);

                }

               byte[] data = bos.toByteArray();

               return new String(data);

            }

        } catch(IOException e) {

            throwe;

        } finally {

            if (fis!= null) {

                try{

                   fis.close();

                }catch (IOException e) {

                   e.printStackTrace();

                }

            }

            if (bos!= null) {

                try{

                   bos.close();

                }catch (IOException e) {

                   e.printStackTrace();

                }

            }

        }

        return"";

    }

 

    /**

     * 移除缓存

     */

    public booleanremoveCache(String key) {

        if(mDiskLruCache != null) {

            try {

               return mDiskLruCache.remove(encryptMD5(key));

            } catch(IOException e) {

               e.printStackTrace();

            }

        }

        returnfalse;

    }

 

    /**

     * 获取缓存目录

     */

    private FilegetDiskCacheDir(Context context, String uniqueName) {

        StringcachePath = context.getCacheDir().getPath();

        return new File(cachePath + File.separator +uniqueName);

    }

 

    /**

     * 获取APP版本号

     */

    private intgetAppVersion(Context context) {

       PackageManager pm = context.getPackageManager();

        try {

           PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);

            returnpi == null ? 0 : pi.versionCode;

        } catch(PackageManager.NameNotFoundException e) {

           e.printStackTrace();

        }

        return 0;

    }

}


实现一个EnhancedCacheInterceptor,拦截post并缓存post请求。实现无网络时读取缓存。

public class EnhancedCacheInterceptor implementsInterceptor {

    @Override

    public Responseintercept(Chain chain) throws IOException {

       LogUtils.e("EnhancedCacheInterceptor");

        Requestrequest = chain.request();

 

        HttpUrlhttpUrl = request.url();

        String url= httpUrl.toString();

        RequestBodyrequestBody = request.body();

        Charsetcharset = Charset.forName("UTF-8");

       StringBuilder sb = new StringBuilder();

       sb.append(httpUrl.queryParameter("method"));

       /*sb.append(url);

        if(request.method().equals("POST")) {

           MediaType contentType = requestBody.contentType();

            if(contentType != null) {

               charset = contentType.charset(Charset.forName("UTF-8"));

            }

            Bufferbuffer = new Buffer();

            try {

               requestBody.writeTo(buffer);

            } catch(IOException e) {

               e.printStackTrace();

            }

           sb.append(buffer.readString(charset));

           buffer.close();

        }*/

       Log.e(CacheManager.TAG, "EnhancedCacheInterceptor -> key:"+ sb.toString());

 

        if(NetworkStateUtils.isNetworkAvailable()) {

           Response response = chain.proceed(request);

           CacheControl cacheControl = request.cacheControl();

           LogUtils.e(cacheControl.toString());

           LogUtils.e("response: " + response.toString());

           LogUtils.e("responseBody : " + response.body().toString());

            if(!cacheControl.noStore()) {

               ResponseBody responseBody = response.body();

               MediaType contentType = responseBody.contentType();

 

               BufferedSource source = responseBody.source();

               source.request(Long.MAX_VALUE);

               Buffer buffer = source.buffer();

 

                if(contentType != null) {

                   charset = contentType.charset(Charset.forName("UTF-8"));

                }

               String key = sb.toString();

                //服务器返回的json原始数据

               String json = buffer.clone().readString(charset);

 

               CacheManager.getInstance().putCache(key, json);

                Log.e(CacheManager.TAG, "putcache-> key:" + key + "-> json:" + json);

            }

            returnresponse;

        } else {

           CacheControl cacheControl = request.cacheControl();

            if(!cacheControl.noStore()) {

                request = request.newBuilder()

                       .cacheControl(CacheControl.FORCE_CACHE)

                       .build();

               String key = sb.toString();

               String cache = CacheManager.getInstance().getCache(key);

                Response originalResponse =chain.proceed(request);

 

               return originalResponse

                       .newBuilder()

                       .code(200)

                       .message("OK")

                       .body(ResponseBody.create(originalResponse.body().contentType(), cache))

                       .build();

            } else{

               return chain.proceed(request);

            }

        }

    }

}


注意,默认在无网络情况下,会返回504 error。这里hack response,强制改回200,并返回缓存数据。

 

Okhttp3结合Retrofit2 实现缓存 Retrofit本身并没有缓存。OkHttp是由Square发布的一个HTTP client,它支持高速缓存服务器响应的语义。如果服务器的响应具有Cache-Control头,例如,它将被缓存,以便随后的请求可以从高速缓存中的获得之前的资源。因此,设备处于断网情况下,Retrofit与Okhttp配合可以实现缓存。Okhttp缓存设计和浏览器设计一样,是用来提升用户体验以及降低浏览器负荷的。项目实际开发过程中,我们使用到的无非两种情景:1.无论是否有网,一定时间段内都是先读缓存,不同的接口根据自己的实时性可 阅读详情

相关推荐

OKHttp3缓存拦截器:Retrofit网络请求的缓存与离线兜底方案

网络缓存是提升App性能和弱网体验的重要手段。HTTP缓存机制通过Cache-Control等响应头决定数据复用方式,但服务端未必返回合适的缓存策略。OkHttp3 Interceptor提供统一的拦截入口,能在请求发出前和响应返回后进行干预,配合Retrofit无需改动业务代码即可为所有接口增加复用能力。在实际工程中,合理设计拦截器可实现同一GET请求在指定时间内不再重复访问服务器,也可在断网时返回已缓存内容,实现离线兜底。从拦截器原理出发,给出基于OkHttp3与Retrofit的缓存拦截器实现,解释m

weixin_30798867的博客 150

Retrofit的原理解析

上篇文章我们分析了OkHttp的原理,不难看出它更多的还是和TCP/IP打交道,做了请求和响应的处理,今天我们来介绍另外一位主人公,那就是我们的,它更多的是对OkHttp做了一层封装,方便了我们调用接口,并且对数据进行了转化,对业务侧更加友好。首先我们来看看它的初始化,慢慢剖析它的源码吧。老相识又出现了Builder,我们接着看。

qq_27391737的博客 535

OKHttp3网络缓存实战:Interceptor拦截器与Retrofit集成方案

HTTP缓存是提升客户端网络请求效率的重要手段,而Android开发中OkHttp作为最常用的网络库,其拦截器机制为实现自定义缓存提供了灵活扩展点。应用拦截器位于请求执行链路的顶层,既能在不触发真实网络请求的情况下直接回放本地响应,又能与Retrofit透明协作,避免修改业务接口代码。针对后端未配置Cache-Control、列表接口重复拉取以及弱网环境下的加载问题,通过自研Interceptor按URL对GET请求进行磁盘缓存,结合TTL策略实现接口级数据保鲜。本文剖析应用拦截器与网络拦截器的差异,演示如

weixin_33670640的博客 247

Android 使用Retrofit2.0+OkHttp3.0实现缓存处理+Cookie持久化第三方库

1.Retrofit+OkHttp的缓存机制 1.1.第一点 在响应请求之后在 data/data/<包名>/cache 下建立一个response 文件夹,保存缓存数据。 1.2.第二点 这样我们就可以在请求的时候,如果判断到没有网络,自动读取缓存的数据。 1.3.第三点 同样这也可以实现,在我们没有网络...

SFC0511的博客 663

基于Retrofit2,okhttp3的数据缓存(cache)技术(修改了缓存时间,能够设置缓存时间了)

可解决在无网络的情况下设置超时时间,之前很多文章可以实现在有网的情况下设置缓存时间,但是无网的情况下根本没有设置超时时间(设置是设置了,但是不起效果,大家可以测试) 当查找cache的时候,网上基本都是这样的文章,而且内容都这样;把里面的代码弄出来放到了包中,运行不了,真不知道疯狂转载类似文章的人是自己看了文章,实践了之后才疯狂转发的吗?不懂了!反正我是没能实现;然后看了我同学的这篇博客http://blog.youkuaiyun.com/qqyanjiang/article/details/51316116,看下来的感觉也差不多,问题同样没能解决,后来就问我同学了,然后他看了之后说少加了

基于Retrofit2,okhttp3的数据缓存(cache)技术

当查找cache的时候,网上基本都是[这样的文章,而且内容都这样;](http://blog.qiji.tech/archives/1690)把里面的代码弄出来放到了包中,运行不了,真不知道疯狂转载类似文章的人是自己看了文章,实践了之后才疯狂转发的吗?不懂了!反正我是没能实现;然后看了我同学的这篇博客[http://blog.youkuaiyun.com/qqyanjiang/article/details/51316116](http://blog.youkuaiyun.com/qqyanjiang/article/details/51316116),看下来的感觉也差不多,问题同样没能解决,后来就问我同学了,然后他看了之后说少加了

Retrofit+RxJava实战日志(5)-如何获取缓存

首先OKHttp启用缓存目录OkHttpClient mOkHttpClient = new OkHttpClient(); File cacheDirectory = new File(context.getApplicationContext() .getCacheDir().getAbsolutePath(), "HttpCache"); //指定缓存路径 Cache

3983

OKHttp3(支持Retrofit)的网络数据缓存Interceptor拦截器的实现

本篇文章主要介绍了OKHttp3(支持Retrofit)的网络数据缓存Interceptor拦截器的实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求

本文转载自:http://www.jianshu.com/p/9c3b4ea108a7 使用Retrofit和Okhttp实现网络缓存,更新于2016.02.02 本文使用 Retrofit2.0.0-beta2、Okhttp 2.6.0(Okhttp3.0之后api写法有变化) 配置Okhttp的Cache配置请求头中的cache-control或者统一处理所有请求的请

liuye066的专栏 328

DELL Precision T7920加装显卡遇到的坑

文章目录DELL Precision T7920加装显卡服务器原有配置介绍选购过程确认型号确认PCIE x16插槽确认电源功率和电源线安装过程电源模组线不够多单装一个3090显卡尺寸问题加装上1080Ti非常重要!官方文档 DELL Precision T7920加装显卡 实验室由于显卡计算能力不够,以及显卡显存不够,请老师花了大价钱购入了两张GeForce 3090显卡。老师赛高!记录一下这次加装显卡过程中学到的一些知识。 服务器原有配置介绍 服务器原有一张1080Ti显卡,一个16核Xeon CPU。

weixin_45520982的博客 1万+

【数学基础】基于欧拉角表达的旋转顺序

欧拉角旋转顺序

FalschxMico 1384

android 离线缓存方案,【Android】Retrofit框架缓存处理(离线缓存等)

1.简述上一篇介绍了Retrofit的基本使用,如果您还不了解请先查看Retrofit使用详解–有些相见恨晚 这篇文章;我们在开发app的时候,有一种情况不得不处理,就是在用户断网的清空下的一些页面显示和网络请求响应等一些情况的处理,在无网络的情况下,我们可以给一个默认的友好的提示页面,像这样: 但是有时候有些需求是在无网络连接的情况下也需要显示数据,所以我们就可以通过缓存响应数据,在无网络的情况...

weixin_30769779的博客 427

使用 ANSYS AEDT(双向耦合)对高功率射频同轴滤波器进行热分析

使用 ANSYS HFSS,可以精确计算 EM 损耗,然后将其导入 ANSYS 热分析并使用 ANSYS Icepak CFD 求解器进行仿真,以帮助工程师解决最复杂的热挑战,并预测其设计在温度变化下的表现。然后,RF 损耗将与 ANSYS Icepak CFD 求解器耦合,以执行热分析,包括传热的传导、对流和辐射模式,并计算温度曲线。在此演示中,我们将仿真下面的 RF 同轴滤波器,并计算由于所用材料的有限电导率和介电损耗而导致的 RF 传导损耗。设置 HFSS 设计后,我们可以开始 HFSS 仿真。

jkh920184196的博客 1051

android缓存过期时间,使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求...

使用Retrofit和Okhttp实现网络缓存,更新于2016.02.02本文使用 Retrofit2.0.0-beta2、Okhttp 2.6.0(Okhttp3.0之后api写法有变化)配置Okhttp的Cache配置请求头中的cache-control或者统一处理所有请求的请求头云端配合设置响应头或者自己写拦截器修改响应头中cache-control最后实现的效果是:有网的时候根据你每个接口...

weixin_39860732的博客 531

《阵列信号处理及MATLAB实现》阵列响应矩阵(均匀线阵、均匀圆阵、L型阵列、平面阵列和任意阵列)

《阵列信号处理及MATLAB实现》内容总结,如需阅读更详细内容请购买正版书籍。

APPLECHARLOTTE的博客 1万+

Puchem化合物数据批量抓取采集_宝典_教程_Python爬虫

本文共计6500字,导出到PDF达42页(含代码)。从0教你如何抓取Pubchem化合物数据。 1、 Pubchem介绍 ​ Pubchem是美国国立卫生研究院(NIH)的开放式化学数据库,自2004年推出以来,pubchem已成为科学家、学生和公众的重要化学信息资源。其专门针对化学结构搜索,是网络药理学研究经常用到的数据库之一,不仅使用方便而且免费。 ​ PubChem主要包含小分子,但也包含较大的分子,例如核苷酸,碳水化合物,脂质,肽和化学修饰的大分子。收集有关化学结构,标识符,化学和物理性..

qq_34843422的博客 6073

使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求 (转)...

使用Retrofit和Okhttp实现网络缓存,更新于2016.02.02原文链接:http://www.jianshu.com/p/9c3b4ea108a7本文使用 Retrofit2.0.0-beta2、Okhttp 2.6.0(Okhttp3.0之后api写法有变化)配置Okhttp的Cache配置请求头中的cache-control或者统一处理所有请求的请求头云端配合设置响应头或者自己写拦...

weixin_30367873的博客 239

Pydoll浏览器自动化框架教程

让浏览器自动化回归本质。不再纠缠驱动兼容、不再手动处理验证码、不再因为请求和 UI 分裂而头疼。如果你经常做 Web 自动化、爬虫或者测试,不妨试试 Pydoll。也别忘了给项目点个 ⭐,让作者知道有人喜欢这个工具。👉GitHub 地址。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 204

Retrofit—okhttp Cache缓存策略

为什么要使用cache? 往往我们在请求完一次后,再想请求同样的内容,我们不想再从服务端获取,而是从第一次访问的时候保存下来的数据请求,这样有利于减少访问时间、降低网络负荷。 ok,我们知道需求以后,就得看下Cache有哪些东西。 http缓存相关头 1.Expires (实体标头,HTTP 1.0+) 一个GMT时间,试图告知客户端,在此日期内,可以

fanenqian的博客 1142

大数据安全 | 期末复习(上)| 补档

大数据定义:无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

知识库搭建ing 2589

从VLM到VLA概论

智驾视觉大模型

xiaomu_347的博客 1712

java中使用okhttpsoap,Android okHttp网络请求之Retrofit+Okhttp+RxJava组合

Retrofit介绍:Retrofit和okHttp师出同门,也是Square的开源库,它是一个类型安全的网络请求库,Retrofit简化了网络请求流程,基于OkHtttp做了封装,解耦的更彻底:比方说通过注解来配置请求参数,通过工厂来生成CallAdapter,Converter,你可以使用不同的请求适配器(CallAdapter), 比方说RxJava,Java8, Guava。你可以使用不同...

weixin_30764401的博客 458

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Android Retrofit 网络请求+Ok拦截器+三级缓存

  //需要的自提   public class RetrofitManager {     private static RetrofitManager mRetrofitManager;     private final Retrofit mRetrofit;     private static String BASE_URL = "https://www.zhaoapi.cn...

as89751的博客 780

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

android 网络请求管理 简书,解析android项目中的网络请求

项目一项目中网络请求偶有出现:日志一D/libc-netbsd: [getaddrinfo]: hostname=api1.51zhenghao.cn; servname=(null);app_uid=10332; ai_addrlen=0; ai_canonname=(null); ai_flags=1024;ai_family=0 from prox result 0日志二W/System....

weixin_36036343的博客 563

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Android Retrofit Client的简单实践

Android Retrofit Client的简单封装 前言 Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。 使用 添加build.grade依赖 dependencies { compile 'io.reactivex.rxjava2:rxjava:2.0.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'com.squareup.retrofit2:retrofit:2.0.

研究员的自我修养 1261
上一篇: Proxy——代理模式
下一篇: HTTP头中的Content-Transfer-Encoding
hunter800421
博客等级 码龄22年 60粉丝 97原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值