1 故事背景
- 最近項目上有個業務需求,翻譯成技術需求,即:將
request.headers
中的幾個header
入參轉換成request.body(pageRequest)
中的內置參數。
爲便於靈活配置,header 參數名稱是動態可配置的(存放於nacos配置中心),比如:
sysCode
、Accept-Language
- 技術實現,主要就
springmvc
的org.springframework.web.bind.WebDataBinder
,並結合javax.servlet.http.HttpServletRequest
,實現將header中的指定參數轉發至request.body(pageRequest).params
中
核心代碼如下:
@RestController("cn.johnnyzen.bd.dataservice.biz.dataservice.controller.v2.CommonSearchController")
@Validated
@Api(tags = "DATA2API Controller # V2")
public class CommonSearchController implements DataServiceOpenApi {
// ...
@Autowired
private ServiceConfig serviceConfig;
// ...
@InitBinder
public void forwardedHeadersToParamsDataBinder(WebDataBinder binder, HttpServletRequest request) {
//判斷是否啓用本特性
ForwardedHeaders forwardedHeaders = serviceConfig.getForwardedHeaders();
if(ObjectUtils.isEmpty(forwardedHeaders) || forwardedHeaders.getEnable().equals(Boolean.FALSE)){
logger.warn("Fail to forward headers to body's params because that `service-config.forwardedHeaders` be empty or not enabled!");
return ;
}
logger.info("Start to forward request's headers to request body params with `service-config.forwardedHeaders`,config data as follows : \n{}", forwardedHeaders);
//獲取被綁定對象----PageRequest
PageRequest<Map<String,Object>> pageRequest = (PageRequest<Map<String, Object>>) binder.getTarget();
if(ObjectUtils.isEmpty(pageRequest) || ObjectUtils.isEmpty(pageRequest.getParams())){
logger.error("`request.body(pageRequest)` or `request.body(pageRequest).params` is empty!");
return;
}
Map<String,Object> dynamicParams = pageRequest.getParams();
List<ForwardHeaderToParamConfig> forwardHeaderToParamConfigList = forwardedHeaders.getHeaders();
forwardHeaderToParamConfigList.stream().forEach(forwardedHeaderConfig -> {
//獲取目標header參數值,並轉發至params中
String headerName = forwardedHeaderConfig.getHeader();
String headerValue = request.getHeader( forwardedHeaderConfig.getHeader() );
String paramName = forwardedHeaderConfig.getParam();
logger.debug("headerName:{}, headerValue:{}, paramName:{}", headerName, headerValue, paramName);
dynamicParams.put(paramName, headerValue);
});
}
// ...
}
- 那麼,我寫這篇博客的目的是什麼呢?
- 你有沒有這麼一個疑惑:
request.getHeader(headerName)
,這個基於Tomcat.catalina
實現的方法,是否區分headerName
的大小寫?
如果不區分大小寫,那還好辦;如果區分大小寫,就尷尬了————我將需要將
Accept-Language
的每一種字母大小寫的可能性都要一一進行配置!
經過源碼分析,答案是:request.getHeader(headerName)
不區分大小寫!
感興趣的朋友,可以進入第2章節,一起看看源碼
2 源碼分析
- springmvc: 5.2.15.RELEASE
- springboot: 2.3.12.RELEASE
- tomcat-embed: 9.0.46 (springboot內嵌的tomcat)
- 調試工具: IDEA
Step1 javax.servlet.http.HttpServletRequest : request.getHeader("Accept-Language")
import javax.servlet.http.HttpServletRequest;
//...
request.getHeader("Accept-Language")
//...
Step2 javax.servlet.http.HttpServletRequest#getHeader
javax.servlet.http.HttpServletRequest#getHeader
Step3 org.apache.catalina.connector.Request#getHeader
特別說明:
org.apache.catalina.connector.Request#getHeader
其實現了接口:javax.servlet.http.HttpServletRequest#getHeader
org.apache.catalina.connector.Request#getHeader
Step4 org.apache.coyote.Request#getHeader
org.apache.coyote.Request#getHeader
Step5 org.apache.tomcat.util.http.MimeHeaders#getHeader
org.apache.tomcat.util.http.MimeHeaders#getHeader
Step6 org.apache.tomcat.util.http.MimeHeaders#getValue(java.lang.String)
org.apache.tomcat.util.http.MimeHeaders#getValue(java.lang.String)
X 參考文獻
無