OkHttp3源码(三)------Header

由于Header类是之前已经分析好的,所以这里直接拿过来就可以了。
之所以之前没有发布这篇博客是因为在学习Header类之前,首先要明白Http首部信息的相关字段及内容,关于这个如果还不太了解请参看 Http首部的字段及相应的取值内容

Header类属性:

  //通过字符串数据的方式维护数据,用于实现获取数据的功能。
    private final String[] namesAndValues;

Header类只有一个属性,这个属性的含义已表明。

Header类的构造方法

    Headers(Builder builder) {
        this.namesAndValues = builder.namesAndValues.toArray(new String[builder.namesAndValues.size()]);
    }

    private Headers(String[] namesAndValues) {
        this.namesAndValues = namesAndValues;
    }

通过Header类的构造方法我们知道,对于用户来说它是禁止new的。所以实例化该类的方法另有其它。

实例化Header类的方法

    //实例化Header并检查传递的数据是否合法,然后设置字符串数组。
    public static Headers of(String... namesAndValues) {
        if (namesAndValues == null) throw new NullPointerException("namesAndValues == null");
        if (namesAndValues.length % 2 != 0) {
            throw new IllegalArgumentException("Expected alternating header names and values");
        }

        namesAndValues = namesAndValues.clone();
        for (int i = 0; i < namesAndValues.length; i++) {
            if (namesAndValues[i] == null) throw new IllegalArgumentException("Headers cannot be null");
            namesAndValues[i] = namesAndValues[i].trim();
        }

        for (int i = 0; i < namesAndValues.length; i += 2) {
            String name = namesAndValues[i];
            String value = namesAndValues[i + 1];
            if (name.length() == 0 || name.indexOf('\0') != -1 || value.indexOf('\0') != -1) {
                throw new IllegalArgumentException("Unexpected header: " + name + ": " + value);
            }
        }
        return new Headers(namesAndValues);
    }

    //实例化Header类并检查数据的合法性,然后通过Map集合设置字符串数组,
    public static Headers of(Map<String, String> headers) {
        if (headers == null) throw new NullPointerException("headers == null");
        String[] namesAndValues = new String[headers.size() * 2];
        int i = 0;
        for (Map.Entry<String, String> header : headers.entrySet()) {
            if (header.getKey() == null || header.getValue() == null) {
                throw new IllegalArgumentException("Headers cannot be null");
            }
            String name = header.getKey().trim();
            String value = header.getValue().trim();
            if (name.length() == 0 || name.indexOf('\0') != -1 || value.indexOf('\0') != -1) {
                throw new IllegalArgumentException("Unexpected header: " + name + ": " + value);
            }
            namesAndValues[i] = name;
            namesAndValues[i + 1] = value;
            i += 2;
        }
        return new Headers(namesAndValues);
    }

   //通过Builder实例化Headers类,并将自身的List集合传递过去。
   public Headers build() {
        return new Headers(this);
     }

我们可以看到上面三个方法可以实例化Header类,前两个是Header类的两个静态方法,最后一个是Header类的内部类Builder的成员方法。

Headler类中根据首部字段名获取值的方法

    //获得字符串数组中名称为name的头信息,如果名称为name的头信息由多个,则返回最先加入的一个。
    private static String get(String[] namesAndValues, String name) {
        for (int i = namesAndValues.length - 2; i >= 0; i -= 2) {
            if (name.equalsIgnoreCase(namesAndValues[i])) {
                return namesAndValues[i + 1];
            }
        }
        return null;
    }

    //获得名称为name的最先添加的头信息
    public String get(String name) {
        return get(namesAndValues, name);
    }

    //根据名称获得与日期有关的头信息,并将日期格式化成Http数据格式
    public Date getDate(String name) {
        String value = get(name);
        return value != null ? HttpDate.parse(value) : null;
    }
   //返回所有名称为name的头信息
    public List<String> values(String name) {
        List<String> result = null;
        for (int i = 0, size = size(); i < size; i++) {
            if (name.equalsIgnoreCase(name(i))) {
                if (result == null) result = new ArrayList<>(2);
                result.add(value(i));
            }
        }
        return result != null
                ? Collections.unmodifiableList(result)
                : Collections.<String>emptyList();
    }

Header类中根据脚标获得首部字段名称或首部字段值的方法

    //根据脚标获得头信息的名称
    public String name(int index) {
        return namesAndValues[index * 2];
    }

    //根据脚标获得头信息
    public String value(int index) {
        return namesAndValues[index * 2 + 1];
    }

Header类中其它方法

    //返回所有头信息的名称
    public Set<String> names() {
        TreeSet<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        for (int i = 0, size = size(); i < size; i++) {
            result.add(name(i));
        }
        return Collections.unmodifiableSet(result);
    }

    //返回所有头信息的长度
    public int size() {
        return namesAndValues.length / 2;
    }

    //将名称相同的头信息放在一起组成List,并和名称组成Map集合
    public Map<String, List<String>> toMultimap() {
        Map<String, List<String>> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        for (int i = 0, size = size(); i < size; i++) {
            String name = name(i).toLowerCase(Locale.US);
            List<String> values = result.get(name);
            if (values == null) {
                values = new ArrayList<>(2);
                result.put(name, values);
            }
            values.add(value(i));
        }
        return result;
    }

Headler类中内部类——Builder

  /**
     * 接下来就是Builder设计模式
     * OkHttp用的比较多的设计模式
     * 对Builder模式不了解的,先去了解下。这里概括一下Builder模式:类的某些字段无法通过自身去赋值,需要委托给其他类去赋值。
     */
    public static final class Builder {
        //Builder里面通过维护List集合实现动态增加
        final List<String> namesAndValues = new ArrayList<>(20);

        //检查头部信息名称和头部信息合法性(不允许为空,且不能包括“非法字符”)
        private void checkNameAndValue(String name, String value) {
            if (name == null) throw new NullPointerException("name == null");
            if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
            for (int i = 0, length = name.length(); i < length; i++) {
                char c = name.charAt(i);
                if (c <= '\u0020' || c >= '\u007f') {
                    throw new IllegalArgumentException(Util.format(
                            "Unexpected char %#04x at %d in header name: %s", (int) c, i, name));
                }
            }
            if (value == null) throw new NullPointerException("value == null");
            for (int i = 0, length = value.length(); i < length; i++) {
                char c = value.charAt(i);
                if ((c <= '\u001f' && c != '\t') || c >= '\u007f') {
                    throw new IllegalArgumentException(Util.format(
                            "Unexpected char %#04x at %d in %s value: %s", (int) c, i, name, value));
                }
            }
        }

        //增加头部信息(可以理解为增加一种特殊的键值对,规则是 key:value、"":value、value 这三种方式)
        Builder addLenient(String line) {
            int index = line.indexOf(":", 1);
            if (index != -1) {
                return addLenient(line.substring(0, index), line.substring(index + 1));
            } else if (line.startsWith(":")) {
                // Work around empty header names and header names that start with a
                // colon (created by old broken SPDY versions of the response cache).
                return addLenient("", line.substring(1)); // Empty header name.
            } else {
                return addLenient("", line); // No header name.
            }
        }

        //增加头部信息(可以理解为增加一种特殊的键值对,规则是 key:value  这一种方式)
        public Builder add(String line) {
            int index = line.indexOf(":");
            if (index == -1) {
                throw new IllegalArgumentException("Unexpected header: " + line);
            }
            return add(line.substring(0, index).trim(), line.substring(index + 1));
        }

        //增加头部信息名称和相应的头部信息(这个是增加,并不会删除原有相同名称的头部信息)
        public Builder add(String name, String value) {
            checkNameAndValue(name, value);
            return addLenient(name, value);
        }

        //增加头部信息的name和相应的头部信息。
        Builder addLenient(String name, String value) {
            namesAndValues.add(name);
            namesAndValues.add(value.trim());
            return this;
        }

        //设置唯一的头部信息(添加这个头部信息前,先要删除所有与这个头部名称相同的头部信息)
        public Builder set(String name, String value) {
            checkNameAndValue(name, value);
            removeAll(name);
            addLenient(name, value);
            return this;
        }
        //清除所有名称为name的头部信息
        public Builder removeAll(String name) {
            for (int i = 0; i < namesAndValues.size(); i += 2) {
                if (name.equalsIgnoreCase(namesAndValues.get(i))) {
                    namesAndValues.remove(i); // name
                    namesAndValues.remove(i); // value
                    i -= 2;
                }
            }
            return this;
        }

        //根据名称获得最先加入的头部信息
        public String get(String name) {
            for (int i = namesAndValues.size() - 2; i >= 0; i -= 2) {
                if (name.equalsIgnoreCase(namesAndValues.get(i))) {
                    return namesAndValues.get(i + 1);
                }
            }
            return null;
        }
        //通过Builder实例化Headers类,并将自身的List集合传递过去。
        public Headers build() {
            return new Headers(this);
        }
    }

Header类主要是通过List集合的方式实现动态添加和删除首部字段信息,通过字符串数组的方式实现获取首部字段信息。

猜你喜欢

转载自blog.csdn.net/look_Future/article/details/79714183