HTTP标头密钥可以重复吗?

lia*_*lun 2 header http

在JAVA HttpUrlConnection中,请求Header设置的主要逻辑代码如下:

public synchronized void set(String k, String v) {
        for (int i = nkeys; --i >= 0;)
            if (k.equalsIgnoreCase(keys[i])) {
                values[i] = v;
                return;
            }
        add(k, v);
}
Run Code Online (Sandbox Code Playgroud)

验证密钥应该是唯一的,密钥必须与值保持一对一的映射关系.

相反,在HeaderFields of Response模块中,结构定义为Entry>.也就是说,密钥不与该值保持一对一的映射关系.

为什么是这样?HTTP协议是否有相关协议?

添加:在HttpClient4中,请求Header设置的主要逻辑代码如下:

 /**
 * Replaces the first occurence of the header with the same name. If no header with
 * the same name is found the given header is added to the end of the list.
 *
 * @param header the new header that should replace the first header with the same
 * name if present in the list.
 */
public void updateHeader(final Header header) {
    if (header == null) {
        return;
    }
    // HTTPCORE-361 : we don't use the for-each syntax, i.e.
    //     for (Header header : headers)
    // as that creates an Iterator that needs to be garbage-collected
    for (int i = 0; i < this.headers.size(); i++) {
        final Header current = this.headers.get(i);
        if (current.getName().equalsIgnoreCase(header.getName())) {
            this.headers.set(i, header);
            return;
        }
    }
    this.headers.add(header);
}
Run Code Online (Sandbox Code Playgroud)

回应的标题

/**
 * Gets all of the headers with the given name.  The returned array
 * maintains the relative order in which the headers were added.
 *
 * <p>Header name comparison is case insensitive.
 *
 * @param name the name of the header(s) to get
 *
 * @return an array of length >= 0
 */
public Header[] getHeaders(final String name) {
    final List<Header> headersFound = new ArrayList<Header>();
    // HTTPCORE-361 : we don't use the for-each syntax, i.e.
    //     for (Header header : headers)
    // as that creates an Iterator that needs to be garbage-collected
    for (int i = 0; i < this.headers.size(); i++) {
        final Header header = this.headers.get(i);
        if (header.getName().equalsIgnoreCase(name)) {
            headersFound.add(header);
        }
    }

    return headersFound.toArray(new Header[headersFound.size()]);
}
Run Code Online (Sandbox Code Playgroud)

它们与HttpUrlConnection相同

Rem*_*eau 7

HTTP协议是否有相关协议?

是. RFC 2616第4.2节"消息标题"说:

当且仅当该头字段的整个字段值被定义为以逗号分隔的列表[即,#(值)]时,具有相同字段名的多个消息头字段可以存在于消息中. 必须可以将多个头字段组合成一个"字段名:字段 - 值"对,而不改变消息的语义,方法是将每个后续字段值附加到第一个字段值,每个字段值用逗号分隔.因此,接收具有相同字段名称的头字段的顺序对于组合字段值的解释是重要的,因此代理不能在转发消息时改变这些字段值的顺序.

RFC 7230第3.2.2节"字段顺序"进一步扩展了这一点:

发件人不得在邮件中生成具有相同字段名称的多个标题字段,除非该标题字段的整个字段值定义为逗号分隔列表[即#(值)]或标题字段是否为已知异常(如下所述).

接收者可以与相同的字段名称组合多个报头字段为一个"字段名:字段值"对,在不改变消息的语义,通过每个随后的字段值追加到为了所述组合字段值,由一个分离的逗号. 因此,接收具有相同字段名称的头字段的顺序对于组合字段值的解释是重要的; 代理不得在转发消息时更改这些字段值的顺序.