[Servlet/Tomcat] HttpServletRequest#getHeader(headerNameWithIgnoreCase)(獲取header時不區分大小寫)

1 故事背景

  • 最近項目上有個業務需求,翻譯成技術需求,即:將request.headers中的幾個header入參轉換成request.body(pageRequest)中的內置參數。

爲便於靈活配置,header 參數名稱是動態可配置的(存放於nacos配置中心),比如:sysCodeAccept-Language

  • 技術實現,主要就 springmvcorg.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 參考文獻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章