OkHttp之Headers请求头

Quibbler 2021-3-14 1504

OkHttp之Headers请求头


        前面看了请求Request和请求体RequestBody类实现源码,最后我们来看看请求头HeadersHeaders是HTTP请求和相应的头部所包含的信息:MIME、日期、缓存、Cookie等。


1、Headers

        OkHttp设计的Headers类结构如下,让我们仔细看看其中的实现。



1.1、核心成员

        Headers类内部并没有用两个数组分别维护请求头中的name和value值。而是用一个集合namesAndValues维护两份一一对应的数据:name和values。这样做适合请求头信息直接发送和解析,省去网络请求的时候再对头部信息进行拼接处理。

    private val namesAndValues: Array<String>

        在集合中Headers信息的存储是:[name1,value1,name2,value2,name3,value3,... ],所以Headers的大小size是数据集合namesAndValues的一半,

    /** Returns the number of field values. */
    val size: Int
        get() = namesAndValues.size / 2


1.2、获取Header信息

        获取Headers数据,value紧接着name存储。

    /** Returns the field at `position`. */
    fun name(index: Int): String = namesAndValues[index * 2]
  
    /** Returns the value at `index`. */
    fun value(index: Int): String = namesAndValues[index * 2 + 1]


1.3、获取name和values

        通过names()方法可以获取Headers请求头中所有不重复的name集合:

    fun names(): Set<String> {
        val result = TreeSet(String.CASE_INSENSITIVE_ORDER)
        for (i in 0 until size) {
          result.add(name(i))
        }
        return Collections.unmodifiableSet(result)
    }

        借助values(name )可以获取values集合。有点奇怪,为什么获取的values会是集合,一个name不只对应一个value吗?为什么可以用一个name获取values的集合呢?后面看到通过Builder添加name-value的方法就可以发现,name是可以重复添加的,这会导致同一个name可能对应多个values。所以会返回重复name的所有value。

  /** Returns an immutable list of the header values for `name`. */
  fun values(name: String): List<String> {
    var result: MutableList<String>? = null
    for (i in 0 until size) {
      if (name.equals(name(i), ignoreCase = true)) {
        if (result == null) result = ArrayList(2)
        result.add(value(i))
      }
    }
    return if (result != null) {
      Collections.unmodifiableList(result)
    } else {
      emptyList()
    }
  }



2、Builder

        不能直接通过构造方法创建Headers实例,而应该通过Builder构建Headers实例。


2.1、集合成员

        内部也是用一个可修改集合namesAndValues保存,最后将用于构造Headers实例。

    internal val namesAndValues: MutableList<String> = ArrayList(20)


2.2、添加Header信息

        通过向Headers中添加头部信息,了解Headers是如何用一个集合namesAndValues存储K-V的。以add(name,value)为例:

    fun add(name: String, value: String) = apply {
      checkName(name)
      checkValue(value, name)
      addLenient(name, value)
    }

        先校验name和value的合法性,再调用内部方法addLenient(name,value)完成请求头信息添加。其它add方法也是如此。

    /**
     * Add a field with the specified value without any validation. Only appropriate for headers
     * from the remote peer or cache.
     */
    internal fun addLenient(name: String, value: String) = apply {
      namesAndValues.add(name)
      namesAndValues.add(value.trim())
    }

        如果Headers中已有name需要更新,应使用set(name,value)方法,否者会添加重复的name到namesAndValues集合中。

    /**
     * Set a field with the specified value. If the field is not found, it is added. If the field is
     * found, the existing values are replaced.
     */
    operator fun set(name: String, value: String) = apply {
      checkName(name)
      checkValue(value, name)
      removeAll(name)
      addLenient(name, value)
    }

        还有很多其它添加请求头信息的便捷方法,就不一一列出。开发者在开发中应当以源码为准,实时查看源码的实现。


2.3、校验name和values

        Headers内部提供两个check静态方法,用于校验Headers请求头中的name和value是否有效,checkName(name)方法实现如下,如果加了什么奇怪的name导致失败,最好来这里看看原因。

    private fun checkName(name: String) {
      require(name.isNotEmpty()) { "name is empty" }
      for (i in 0 until name.length) {
        val c = name[i]
        require(c in '\u0021'..'\u007e') {
          format("Unexpected char %#04x at %d in header name: %s", c.toInt(), i, name)
        }
      }
    }

        checkValue(value ,name)校验value值实现如下:

    private fun checkValue(value: String, name: String) {
      for (i in 0 until value.length) {
        val c = value[i]
        require(c == '\t' || c in '\u0020'..'\u007e') {
          format("Unexpected char %#04x at %d in %s value: %s", c.toInt(), i, name, value)
        }
      }
    }


        连着两天把RequestRequestBodyHeaders都看完了,对其内部的实现都已经非常清楚。接下来就开始撸OkHttp网络请求流程。



不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com