Okhttp3源碼解析(2)-Request分析

###前言
前面我們講了
Okhttp的基本用法
Okhttp3源碼解析(1)-OkHttpClient分析

今天主要分析下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模式!

我們點擊Request源碼進去,果然 其中有靜態的Builder內部類:

然後我們查一下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是可以的

如果是POST請求,就需要我們去設定了

RequestBody解析

首先我們看一下RequestBody如何初始化??拿提交表單舉例:

    RequestBody requestBody = new FormBody.Builder()
                .add("username", "qinzishuai")
                .add("password", "000000")
                .build();

不出所料,也是Builder模式,而且RequestBody 是抽象類, FormBodyRequestBody的其中一種實現類 ,另一個實現類是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) //寫操作

今天就講到這裏,希望對大家有所幫助…

大家可以關注我的微信公衆號:「秦子帥」一個有質量、有態度的公衆號!

公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章