2024年Java最新OkHttp3源码详解(一) Request类,java面试笔试题代码

最后

为什么我不完全主张自学?
平台上的大牛基本上都有很多年的工作经验了,你有没有想过之前行业的门槛是什么样的,现在行业门槛是什么样的?以前企业对于程序员能力要求没有这么高,甚至十多年前你只要会写个“Hello World”,你都可以入门这个行业,所以以前要入门是完全可以入门的。
②现在也有一些优秀的年轻大牛,他们或许也是自学成才,但是他们一定是具备优秀的学习能力,优秀的自我管理能力(时间管理,静心坚持等方面)以及善于发现问题并总结问题。
如果说你认为你的目标十分明确,能做到第②点所说的几个点,以目前的市场来看,你才真正的适合去自学。

除此之外,对于绝大部分人来说,报班一定是最好的一种快速成长的方式。但是有个问题,现在市场上的培训机构质量参差不齐,如果你没有找准一个好的培训班,完全是浪费精力,时间以及金钱,这个需要自己去甄别选择。

我个人建议线上比线下的性价比更高,线下培训价格基本上没2W是下不来的,线上教育现在比较成熟了,此次疫情期间,学生基本上都感受过线上的学习模式。相比线下而言,线上的优势以我的了解主要是以下几个方面:
①价格:线上的价格基本上是线下的一半;
②老师:相对而言线上教育的师资力量比线下更强大也更加丰富,资源更好协调;
③时间:学习时间相对而言更自由,不用裸辞学习,适合边学边工作,降低生活压力;
④课程:从课程内容来说,确实要比线下讲的更加深入。

应该学哪些技术才能达到企业的要求?(下图总结)

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

OkHttp3中RequestBody有三种创建方式

①方式一:

  1. public static RequestBody create(MediaType contentType, String content) {

  2. Charset charset = Util.UTF_8;

  3. if (contentType != null) {

  4. charset = contentType.charset();//MediaType的为请求头中的ContentType创建方式:public static final MediaType TEXT =

  5. //MediaType.parse(“text/plain; charset=utf-8”)

  6. if (charset == null) {

  7. charset = Util.UTF_8;//如果contentType中没有指定charset,默认使用UTF-8

  8. contentType = MediaType.parse(contentType + “; charset=utf-8”);

  9. }

  10. }

  11. byte[] bytes = content.getBytes(charset);

  12. return create(contentType, bytes);

  13. }

②方式二:FormBody表单创建,我们来看一下

FormBody用于普通post表单上传键值对,我们先来看一下创建的方法,再看源码

  1. RequestBody formBody=new FormBody.Builder()

  2. .add(“name”,“maplejaw”)

  3. .add(")

  4. .build();

FormBody源码

  1. public final class FormBody extends RequestBody {

  2. private static final MediaType CONTENT_TYPE =

  3. MediaType.parse(“application/x-www-form-urlencoded”);

  4. private final List encodedNames;

  5. private final List encodedValues;

  6. private FormBody(List encodedNames, List encodedValues) {

  7. this.encodedNames = Util.immutableList(encodedNames);

  8. this.encodedValues = Util.immutableList(encodedValues);

  9. }

  10. /** The number of key-value pairs in this form-encoded body. */

  11. public int size() {

  12. return encodedNames.size();

  13. }

  14. public String encodedName(int index) {

  15. return encodedNames.get(index);

  16. }

  17. public String name(int index) {

  18. return percentDecode(encodedName(index), true);

  19. }

  20. public String encodedValue(int index) {

  21. return encodedValues.get(index);

  22. }

  23. public String value(int index) {

  24. return percentDecode(encodedValue(index), true);

  25. }

  26. @Override public MediaType contentType() {

  27. return CONTENT_TYPE;

  28. }

  29. @Override public long contentLength() {

  30. return writeOrCountBytes(null, true);

  31. }

  32. @Override public void writeTo(BufferedSink sink) throws IOException {

  33. writeOrCountBytes(sink, false);

  34. }

  35. /**

    • Either writes this request to {@code sink} or measures its content length. We have one method
    • do double-duty to make sure the counting and content are consistent, particularly when it comes
    • to awkward operations like measuring the encoded length of header strings, or the
    • length-in-digits of an encoded integer.
  36. */

  37. private long writeOrCountBytes(BufferedSink sink, boolean countBytes) {

  38. long byteCount = 0L;

  39. Buffer buffer;

  40. if (countBytes) {

  41. buffer = new Buffer();

  42. } else {

  43. buffer = sink.buffer();

  44. }

  45. , size = encodedNames.size(); i < size; i++) {

  46. ) buffer.writeByte(‘&’);

  47. buffer.writeUtf8(encodedNames.get(i));

  48. buffer.writeByte(‘=’);

  49. buffer.writeUtf8(encodedValues.get(i));

  50. }

  51. if (countBytes) {

  52. byteCount = buffer.size();

  53. buffer.clear();

  54. }

  55. return byteCount;

  56. }

  57. public static final class Builder {

  58. private final List names = new ArrayList<>();

  59. private final List values = new ArrayList<>();

  60. public Builder add(String name, String value) {

  61. names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, false, false, true, true));

  62. values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, false, false, true, true));

  63. return this;

  64. }

  65. public Builder addEncoded(String name, String value) {

  66. names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, true, false, true, true));

  67. values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, true, false, true, true));

  68. return this;

  69. }

  70. public FormBody build() {

  71. return new FormBody(names, values);

  72. }

  73. }

  74. }

``````````````我们主要来看一下方法````````````````writeOrCountBytes``````````````````````````````,通过writeOrCountBytes来计算请求体大小和将请求体写入BufferedSink。

至于BufferSink和Buffer类,这两个类是Okio中的类,Buffer相当于一个缓存区,BufferedSink相当于OutputStream,它扩展了

OutputStream的功能,Okio的完整源码我后续也会写博客

③方式三:MultipartBody分块表单创建

``MultipartBody, 既可以添加表单,又可以也可以添加文件等二进制数据,我们就看几个重要的方法

  1. public static Part createFormData(String name, String filename, RequestBody body) {

  2. if (name == null) {

  3. throw new NullPointerException(“name == null”);

  4. }

  5. StringBuilder disposition = new StringBuilder(“form-data; name=”);

  6. appendQuotedString(disposition, name);

  7. if (filename != null) {

  8. disposition.append(“; filename=”);

  9. appendQuotedString(disposition, filename);

  10. }

  11. return create(Headers.of(“Content-Disposition”, disposition.toString()), body);

  12. }

我们来看这个方法,我们是addPart还是addFormDataPart最终都走到了这个方法,封装成一个Part对象,也就是实体内容中

的Content-Disposition跟文件二进制流或者键值对的值

````````````````MultipartBody和FormBody大体上相同,主要区别在于`writeOrCountBytes方法,分块表单主要是将每个块的大小进行累加来求出请求体大小,如果其中有一个块没有指定大小,就会返回-1。所以分块表单中如果包含文件,默认是无法计算出大小的,除非你自己给文件的RequestBody指定contentLength。`````````````````

  1. private long writeOrCountBytes(BufferedSink sink, boolean countBytes) throws IOException {

  2. long byteCount = 0L;

  3. Buffer byteCountBuffer = null;

  4. if (countBytes) {

  5. //如果是计算大小的话,就new个

  6. sink = byteCountBuffer = new Buffer();

  7. }

  8. //循环块

  9. , partCount = parts.size(); p < partCount; p++) {

  10. Part part = parts.get§;

  11. //获取每个块的头

  12. Headers headers = part.headers;

  13. //获取每个块的请求体

  14. RequestBody body = part.body;

  15. //写 --xxxxxxxxxx 边界

  16. sink.write(DASHDASH);

  17. sink.write(boundary);

  18. sink.write(CRLF);

  19. //写块的头

  20. if (headers != null) {

  21. , headerCount = headers.size(); h < headerCount; h++) {

  22. sink.writeUtf8(headers.name(h))

  23. .write(COLONSPACE)

  24. .writeUtf8(headers.value(h))

  25. .write(CRLF);

  26. }

  27. }

  28. //写块的Content_Type

  29. MediaType contentType = body.contentType();

  30. if (contentType != null) {

  31. sink.writeUtf8("Content-Type: ")

  32. .writeUtf8(contentType.toString())

  33. .write(CRLF);

  34. }

  35. //写块的大小

  36. long contentLength = body.contentLength();

  37. ) {

  38. sink.writeUtf8("Content-Length: ")

  39. .writeDecimalLong(contentLength)

  40. .write(CRLF);

  41. } else if (countBytes) {

  42. // We can’t measure the body’s size without the sizes of its components.

  43. //如果有个块没有这名大小,就返回-1.

  44. byteCountBuffer.clear();

  45. return -1L;

  46. }

  47. sink.write(CRLF);

  48. //如果是计算大小就累加,否则写入BufferedSink

  49. if (countBytes) {

  50. byteCount += contentLength;

  51. } else {

  52. body.writeTo(sink);

  53. }

  54. sink.write(CRLF);

  55. }

  56. //写 --xxxxxxxxxx-- 结束边界

  57. sink.write(DASHDASH);

  58. sink.write(boundary);

  59. sink.write(DASHDASH);

  60. sink.write(CRLF);

  61. if (countBytes) {

  62. byteCount += byteCountBuffer.size();

  63. byteCountBuffer.clear();

  64. }

  65. return byteCount;

  66. }

4.CacheControl

( 1)  Cache-Control:

Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令有下几种:

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

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

  3. no-cache:请求或者响应消息不能缓存

  4. no-store:不使用缓存,也不存储缓存

  5. max-age:缓存的内容将在指定时间(秒)后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高

  6. 在 xxx 秒后,浏览器重新发送请求到服务器,指定时间(秒)内,客户端会直接返回cache而不会发起网络请求,若过期会自动发起网络请求

  7. min-fresh:指示客户端可以接收响应时间小于当前时间加上指定时间的响应。

  8. max-stale:指示客户端可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

(2)CacheControl类

①常用的函数

  1. final CacheControl.Builder builder = new CacheControl.Builder();

  2. builder.noCache();//不使用缓存,全部走网络

  3. builder.noStore();//不使用缓存,也不存储缓存

  4. builder.onlyIfCached();//只使用缓存

  5. builder.noTransform();//禁止转码

  6. builder.maxAge(, TimeUnit.MILLISECONDS);//指示客户机可以接收生存期不大于指定时间的响应。

  7. builder.maxStale(, TimeUnit.SECONDS);//指示客户机可以接收超出超时期间的响应消息

  8. builder.minFresh(, TimeUnit.SECONDS);//指示客户机可以接收响应时间小于当前时间加上指定时间的响应。

  9. CacheControl cache = builder.build();//cacheControl

②CacheControl的两个常量:

  1. public static final CacheControl FORCE_NETWORK = new Builder().noCache().build();//不使用缓存

  2. public static final CacheControl FORCE_CACHE = new Builder()

  3. .onlyIfCached()

  4. .maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS)

  5. .build();//只使用缓存

③请求时如何使用:

最后

在面试前我整理归纳了一些面试学习资料,文中结合我的朋友同学面试美团滴滴这类大厂的资料及案例

MyBatis答案解析
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

大家看完有什么不懂的可以在下方留言讨论也可以关注。

觉得文章对你有帮助的话记得关注我点个赞支持一下!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

al CacheControl FORCE_CACHE = new Builder()

  1. .onlyIfCached()

  2. .maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS)

  3. .build();//只使用缓存

③请求时如何使用:

最后

在面试前我整理归纳了一些面试学习资料,文中结合我的朋友同学面试美团滴滴这类大厂的资料及案例
[外链图片转存中…(img-A2kPDDML-1714925352744)]

[外链图片转存中…(img-fmmSjcFj-1714925352745)]
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

大家看完有什么不懂的可以在下方留言讨论也可以关注。

觉得文章对你有帮助的话记得关注我点个赞支持一下!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.zhy.http.okhttp; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.util.Log; import com.zhy.http.okhttp.cookie.SimpleCookieJar; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Response; import com.zhy.http.okhttp.builder.GetBuilder; import com.zhy.http.okhttp.builder.PostFileBuilder; import com.zhy.http.okhttp.builder.PostFormBuilder; import com.zhy.http.okhttp.builder.PostStringBuilder; import com.zhy.http.okhttp.callback.Callback; import com.zhy.http.okhttp.https.HttpsUtils; import com.zhy.http.okhttp.request.RequestCall; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.TimeUnit; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; /** * Created by zhy on 15/8/17. */ public class OkHttpUtils { public static final String TAG = "OkHttpUtils"; public static final long DEFAULT_MILLISECONDS = 10000; private static OkHttpUtils mInstance; private OkHttpClient mOkHttpClient; private Handler mDelivery; private OkHttpUtils() { OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); //cookie enabled okHttpClientBuilder.cookieJar(new SimpleCookieJar()); mDelivery = new Handler(Looper.getMainLooper()); if (true) { okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); } mOkHttpClient = okHttpClientBuilder.build(); } private boolean debug; private String tag; public OkHttpUtils debug(String tag) { debug = true; this.tag = tag; return this; } public static OkHttpUtils getInstance() { if (mInstance == null) { synchronized (OkHttpUtils.class) { if (mInstance == null) { mInstance = new OkHttpUtils(); } } } return mInstance; } public Handler getDelivery() { return mDelivery; } public OkHttpClient getOkHttpClient() { return mOkHttpClient; } public static GetBuilder get() { return new GetBuilder(); } public static PostStringBuilder postString() { return new PostStringBuilder(); } public static PostFileBuilder postFile() { return new PostFileBuilder(); } public static PostFormBuilder post() { return new PostFormBuilder(); } public void execute(final RequestCall requestCall, Callback callback) { if (debug) { if(TextUtils.isEmpty(tag)) { tag = TAG; } Log.d(tag, "{method:" + requestCall.getRequest().method() + ", detail:" + requestCall.getOkHttpRequest().toString() + "}"); } if (callback == null) callback = Callback.CALLBACK_DEFAULT; final Callback finalCallback = callback; requestCall.getCall().enqueue(new okhttp3.Callback() { @Override public void onFailure(Call call, final IOException e) { sendFailResultCallback(call, e, finalCallback); } @Override public void onResponse(final Call call, final Response response) { if (response.code() >= 400 && response.code() <= 599) { try { sendFailResultCallback(call, new RuntimeException(response.body().string()), finalCallback); } catch (IOException e) { e.printStackTrace(); } return; } try { Object o = finalCallback.parseNetworkResponse(response); sendSuccessResultCallback(o, finalCallback); } catch (Exception e) { sendFailResultCallback(call, e, finalCallback); } } }); } public void sendFailResultCallback(final Call call, final Exception e, final Callback callback) { if (callback == null) return; mDelivery.post(new Runnable() { @Override public void run() { callback.onError(call, e); callback.onAfter(); } }); } public void sendSuccessResultCallback(final Object object, final Callback callback) { if (callback == null) return; mDelivery.post(new Runnable() { @Override public void run() { callback.onResponse(object); callback.onAfter(); } }); } public void cancelTag(Object tag) { for (Call call : mOkHttpClient.dispatcher().queuedCalls()) { if (tag.equals(call.request().tag())) { call.cancel(); } } for (Call call : mOkHttpClient.dispatcher().runningCalls()) { if (tag.equals(call.request().tag())) { call.cancel(); } } } public void setCertificates(InputStream... certificates) { mOkHttpClient = getOkHttpClient().newBuilder() .sslSocketFactory(HttpsUtils.getSslSocketFactory(certificates, null, null)) .build(); } public void setConnectTimeout(int timeout, TimeUnit units) { mOkHttpClient = getOkHttpClient().newBuilder() .connectTimeout(timeout, units) .build(); } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值