-
Notifications
You must be signed in to change notification settings - Fork 327
Description
功能摘要 / Feature Summary
优化fit-framework中的Header设计
功能类型 / Feature Type
全新功能 / New Feature
优先级 / Priority
高 - 非常需要这个功能 / High - Really need this feature
问题描述 / Problem Description
关于fit-framework当前的Header逻辑
modelengine.fit.http.header.HeaderValue
public interface HeaderValue {
/**
* 获取消息头的值。
*
* @return 表示消息头值的 {@link String}。
*/
String value();
/**
* 获取所有参数集合。
*
* @return 表示所有参数集合的 {@link ParameterCollection}。
*/
ParameterCollection parameters();当前的Header值类例如 ContentType 都继承于 HeaderValue ,HeaderValue统一了一套基于value+parameters的模式,是由于例如Content-Type、Content-Disposition、Accept 等都在各自的RFC中定义了这一套格式。
但是在[RFC 9110]§5.5中定义field-value:
field-value = *field-content
field-content = field-vchar
[ 1*( SP / HTAB / field-vchar ) field-vchar ]
field-vchar = VCHAR / obs-text
obs-text = %x80-FF仅定义了字符要求,并没有严格统一的格式。各自Header的格式都在自己的规范中定义。
例如 User-Agent 的 [RFC7321]中说明:
User-Agent = product *( RWS ( product / comment ) )
product = token ["/" product-version]
product-version = token允许以下的值
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...使得当前的Header中固定要求的value+parameters模式很难统一和继承。
建议的解决方案 / Proposed Solution
Spring HttpHeaders + Tomcat中的设计
Spring是依赖于servlet的设计,因此许多关于Header的解析代码都依赖于servlet容器。
servlet标准要求容器提供了以下的接口方法:
public interface HttpServletRequest extends ServletRequest {
String BASIC_AUTH = "BASIC";
String FORM_AUTH = "FORM";
String CLIENT_CERT_AUTH = "CLIENT_CERT";
String DIGEST_AUTH = "DIGEST";
String getAuthType();
Cookie[] getCookies();
long getDateHeader(String var1);
String getHeader(String var1);
Enumeration<String> getHeaders(String var1);
Enumeration<String> getHeaderNames();
int getIntHeader(String var1);
}Tomcat的行为
Tomcat会对接收到的Header进行 field-name : field-value 依照[RFC 9110]
将得到的数据放入 MimeHeaders 类似于 Map<header-key, header-value>。
然后Tomcat会对自己的例如Host,Connection,Content-Length,Transfer-Encoding,Expect等协议层必须依赖的header字段进行解析,剩余的header字段仅保存字节流。
其他的Header主要采用懒加载的方式,在相应的getHeader触发的时候,进行解析成上层类并进行缓存处理,后续调用返回缓存。
Spring的行为
Spring又自行定义了许多上层类。
HttpHeaders implements MultiValueMap<String, String>
然后分别写 getter,setter针对每个Header进行单独序列化和反序列化。(下为片段
org.springframework.http.HttpHeaders )
public void setAccept(List<MediaType> acceptableMediaTypes) {
this.set("Accept", MediaType.toString(acceptableMediaTypes));
}
public List<MediaType> getAccept() {
return MediaType.parseMediaTypes(this.get("Accept"));
}
public void setAcceptLanguage(List<Locale.LanguageRange> languages) {
Assert.notNull(languages, "LanguageRange List must not be null");
DecimalFormat decimal = new DecimalFormat("0.0", DECIMAL_FORMAT_SYMBOLS);
List<String> values = languages.stream().map((range) -> range.getWeight() == (double)1.0F ? range.getRange() : range.getRange() + ";q=" + decimal.format(range.getWeight())).toList();
this.set("Accept-Language", this.toCommaDelimitedString(values));
}
public List<Locale.LanguageRange> getAcceptLanguage() {
String value = this.getFirst("Accept-Language");
return StringUtils.hasText(value) ? LanguageRange.parse(value) : Collections.emptyList();
}
public void setAcceptLanguageAsLocales(List<Locale> locales) {
this.setAcceptLanguage(locales.stream().map((locale) -> new Locale.LanguageRange(locale.toLanguageTag())).toList());
}
public List<Locale> getAcceptLanguageAsLocales() {
List<Locale.LanguageRange> ranges = this.getAcceptLanguage();
return ranges.isEmpty() ? Collections.emptyList() : ranges.stream().map((range) -> Locale.forLanguageTag(range.getRange())).filter((locale) -> StringUtils.hasText(locale.getDisplayName())).toList();
}Spring 的 HttpHeaders 是依赖 servlet 提供的原始 Header 数据,但完全独立于底层的解析逻辑。
修改方案:
是否可以参考 Spring 的做法:底层统一存 String,按需解析到上层对象,而不是在 HeaderValue 接口里强行统一格式。
替代方案 / Alternative Solutions
No response
确认事项 / Confirmations
-
我已经搜索了现有的 issues 和讨论,确认这不是重复建议
I have searched existing issues and discussions, confirming this is not a duplicate suggestion -
这个功能符合项目的目标和范围
This feature aligns with the project's goals and scope -
我理解这个功能可能需要时间来实现
I understand this feature may take time to implement -
我愿意协助实现这个功能 (可选)
I'm willing to help implement this feature (optional)