### 前言 前面我們講了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源碼解析(1)-OkHttpClient分析](https://www.jianshu.com/p/bf1d01b79ce7) 今天主要分析下Req ...
### 前言 前面我們講了 [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)