WebFlux introduced HttpHeaders adapters in Spring Framework 5.1 to map directly to underlying server header API's. Over time a mismatch between MultiValueMap and such header API's became clear.
Typically servers do not store headers in a map, but rather in an ordered collection, e.g. MimeHeaders in Tomcat or HttpFields in Jetty, trading convenience for more efficient access. The loss of efficiency is significant enough, or rather ignoring it can lead to use of innocent looking methods like size() that are inefficient and to real issues like #33823.
In 7.0 HttpHeaders no longer implements MultiValueMap to guide away from Map-like usage, see #33913, adding a dedicated key set to support iterator-based removal, and introducing header-focused alternatives to Map methods.
In 7.0.x we also introduced Servlet API header adapters with #36334, so that both Spring MVC and WebFlux use the header adapter approach.
For 7.1 we can pursue further changes in this direction:
-
decouple adapters from MutliValueMap, and avoid methods that aren't needed in HttpHeaders:
addAll(MultiValueMap<String, String> map)
containsValue(Object rawValue)
putAll(Map<? extends String, ? extends List<String>> map)
values()
entrySet()
Use a more focused contract, e.g. HttpHeadersAdapter and switch existing implementations to it. A default implementation, for new HttpHeaders(), could use LinkedCaseInsensitiveMap internally.
-
take further advantage of a header-focused contract, e.g. the put and remove methods return a List of existing values, which is typically not needed. We could provide void set(List) and use it everywhere instead.
-
The size() method is expensive due to the need to deduplicate across all header fields. We could consider deprecating it in favour of using headerNames() to obtain a set, which would keep it possible, but not as easy, and more clear.
-
HttpHeaders could provide some default implementation of equals/hashcode, useful for testing, so that individual headers adapters don't.
WebFlux introduced
HttpHeadersadapters in Spring Framework 5.1 to map directly to underlying server header API's. Over time a mismatch betweenMultiValueMapand such header API's became clear.Typically servers do not store headers in a map, but rather in an ordered collection, e.g.
MimeHeadersin Tomcat orHttpFieldsin Jetty, trading convenience for more efficient access. The loss of efficiency is significant enough, or rather ignoring it can lead to use of innocent looking methods likesize()that are inefficient and to real issues like #33823.In 7.0
HttpHeadersno longer implementsMultiValueMapto guide away from Map-like usage, see #33913, adding a dedicated key set to support iterator-based removal, and introducing header-focused alternatives to Map methods.In 7.0.x we also introduced Servlet API header adapters with #36334, so that both Spring MVC and WebFlux use the header adapter approach.
For 7.1 we can pursue further changes in this direction:
decouple adapters from
MutliValueMap, and avoid methods that aren't needed inHttpHeaders:Use a more focused contract, e.g.
HttpHeadersAdapterand switch existing implementations to it. A default implementation, fornew HttpHeaders(), could useLinkedCaseInsensitiveMapinternally.take further advantage of a header-focused contract, e.g. the
putandremovemethods return aListof existing values, which is typically not needed. We could providevoid set(List)and use it everywhere instead.The size() method is expensive due to the need to deduplicate across all header fields. We could consider deprecating it in favour of using
headerNames()to obtain a set, which would keep it possible, but not as easy, and more clear.HttpHeaders could provide some default implementation of equals/hashcode, useful for testing, so that individual headers adapters don't.