• Okhttp3源码解析(2)-Request分析


    ### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析](https://www.jianshu.com/p/bf1d01b79ce7) 今天主要分析下Request源码! ### Request初始化 当我们构建完OkHttpClient对象,需要构造Request对象,构造方式如下: ###### 1.Get请求 ``` final Request request=new Request.Builder() .url("https://www.wanandroid.com/navi/json") .get() .build(); ``` ###### 2.POST请求 拿POST提交表单请求,这时就需要声明一个RequestBody对象了 ``` RequestBody requestBody = new FormBody.Builder() .add("username", "qinzishuai") .add("password", "123456") .build(); Request request = new Request.Builder() .url("https://www.wanandroid.com/user/login") .post(requestBody) .build(); ``` 看到上面代码是不是很熟悉?和OkHttpClient很相似, 没错 Request 的构建也是Builder模式! ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823180241877-899976016.png) 我们点击Request源码进去,果然 其中有静态的Builder内部类: ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823180242273-1916386988.png) 然后我们查一下**Request在初始化时配置了哪些参数???** ``` public static class Builder { HttpUrl url; String method; Headers.Builder headers; RequestBody body; public Builder() { this.method = "GET"; this.headers = new Headers.Builder(); } //省略部分代码 public Request build() { if (url == null) throw new IllegalStateException("url == null"); return new Request(this); } } ``` 从代码看到了 如果没有声明,默认是Get请求 ` this.method = "GET"` ,至于`url`等字段需要我们自己去配置: ###### HttpUrl 请求访问的url ,可以传String与URL 具体方法如下: ``` public Builder url(String url) { if (url == null) throw new NullPointerException("url == null"); // Silently replace web socket URLs with HTTP URLs. if (url.regionMatches(true, 0, "ws:", 0, 3)) { url = "http:" + url.substring(3); } else if (url.regionMatches(true, 0, "wss:", 0, 4)) { url = "https:" + url.substring(4); } return url(HttpUrl.get(url)); } public Builder url(URL url) { if (url == null) throw new NullPointerException("url == null"); return url(HttpUrl.get(url.toString())); } ``` ###### method 请求类型 `String method `,支持多种请求类型 ``` public Builder get() { return method("GET", null); } public Builder head() { return method("HEAD", null); } public Builder post(RequestBody body) { return method("POST", body); } public Builder delete(@Nullable RequestBody body) { return method("DELETE", body); } public Builder delete() { return delete(Util.EMPTY_REQUEST); } public Builder put(RequestBody body) { return method("PUT", body); } public Builder patch(RequestBody body) { return method("PATCH", body); } ``` ###### Headers `Headers.Builder ` Http消息的头字段 前面看到了, **我们在初始化Request的时候 同时初始化了headers**, ` this.headers = new Headers.Builder()` 可以通过 `header ` `addHeader ` `removeHeader ` ` headers ` 方法做一些操作 ``` public Builder header(String name, String value) { headers.set(name, value); return this; } public Builder addHeader(String name, String value) { headers.add(name, value); return this; } public Builder removeHeader(String name) { headers.removeAll(name); return this; } public Builder headers(Headers headers) { this.headers = headers.newBuilder(); return this; } ``` ###### body RequestBody类型,它是抽象类, 有些请求需要我们传入body实例 ,我们在通过源码来看一下: 如果是GET请求,body对象传的是null **Get与head方法不能传body对象 ,其他method是可以的** ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823180242513-433063641.png) 如果是POST请求,就需要我们去设定了 ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823180242695-600270897.png) ### RequestBody解析 首先我们看一下RequestBody如何初始化??拿提交表单举例: ``` RequestBody requestBody = new FormBody.Builder() .add("username", "qinzishuai") .add("password", "000000") .build(); ``` 不出所料,也是Builder模式,而且`RequestBody` 是抽象类, `FormBody`是`RequestBody`的其中一种实现类 ,另一个实现类是`MultipartBody` RequestBody源码如下: ``` public abstract class RequestBody { /** Returns the Content-Type header for this body. */ public abstract @Nullable MediaType contentType(); /** * Returns the number of bytes that will be written to {@code sink} in a call to {@link #writeTo}, * or -1 if that count is unknown. */ public long contentLength() throws IOException { return -1; } /** Writes the content of this request to {@code sink}. */ public abstract void writeTo(BufferedSink sink) throws IOException; /** * Returns a new request body that transmits {@code content}. If {@code contentType} is non-null * and lacks a charset, this will use UTF-8. */ public static RequestBody create(@Nullable MediaType contentType, String content) { Charset charset = Util.UTF_8; if (contentType != null) { charset = contentType.charset(); if (charset == null) { charset = Util.UTF_8; contentType = MediaType.parse(contentType + "; charset=utf-8"); } } byte[] bytes = content.getBytes(charset); return create(contentType, bytes); } /** Returns a new request body that transmits {@code content}. */ public static RequestBody create( final @Nullable MediaType contentType, final ByteString content) { return new RequestBody() { @Override public @Nullable MediaType contentType() { return contentType; } @Override public long contentLength() throws IOException { return content.size(); } @Override public void writeTo(BufferedSink sink) throws IOException { sink.write(content); } }; } /** Returns a new request body that transmits {@code content}. */ public static RequestBody create(final @Nullable MediaType contentType, final byte[] content) { return create(contentType, content, 0, content.length); } //省略部分代码... } ``` 核心方法有三个: - contentType()//数据类型 - contentLength()//数据长度 - writeTo(BufferedSink sink) //写操作 今天就讲到这里,希望对大家有所帮助... 大家可以关注我的微信公众号:「秦子帅」一个有质量、有态度的公众号! ![公众号](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823180242882-2108811045.jpg)
  • 相关阅读:
    设计模式之工厂模式-抽象工厂(02)
    1036 跟奥巴马一起编程 (15 分)
    1034 有理数四则运算 (20 分)
    1033 旧键盘打字 (20 分)
    1031 查验身份证 (15 分)
    大学排名定向爬虫
    1030 完美数列 (25 分)二分
    1029 旧键盘 (20 分)
    1028 人口普查 (20 分)
    1026 程序运行时间 (15 分)四舍五入
  • 原文地址:https://www.cnblogs.com/qinzishuai/p/11401790.html
Copyright © 2020-2023  润新知