当前位置: 首页> 教育> 高考 > 小程序开发网站_湖南长沙浏阳最新疫情_百度推广有用吗_哪些浏览器可以看禁止访问的网站

小程序开发网站_湖南长沙浏阳最新疫情_百度推广有用吗_哪些浏览器可以看禁止访问的网站

时间:2025/7/14 4:09:41来源:https://blog.csdn.net/purplesky95/article/details/144916600 浏览次数:0次
小程序开发网站_湖南长沙浏阳最新疫情_百度推广有用吗_哪些浏览器可以看禁止访问的网站

问题复现

  • 在 Spring 中解析 Header 时,我们在多数场合中是直接按需解析的。例如,我们想使用一个名为 myHeaderName 的 Header,我们会书写代码如下:
    @RequestMapping(path = "/hi", method = RequestMethod.GET)
    public String hi(@RequestHeader("myHeaderName") String name){//省略 body 处理
    };
    
  • 定义一个参数,标记上 @RequestHeader,指定要解析的 Header 名即可。但是假设我们需要解析的 Header 很多时,按照上面的方式很明显会使得参数越来越多。在这种情况下,我们一般都会使用 Map 去把所有的 Header 都接收到,然后直接对 Map 进行处理。于是我们可能会写出下面的代码:
    @RequestMapping(path = "/hi1", method = RequestMethod.GET)
    public String hi1(@RequestHeader() Map map){return map.toString();
    };
    
  • 粗略测试程序,你会发现一切都很好。而且上面的代码也符合针对接口编程的范式,即使用了 Map 这个接口类型。但是上面的接口定义在遇到下面的请求时,就会超出预期。请求如下:

    GET http://localhost:8080/hi1
    myheader: h1
    myheader: h2

  • 这里存在一个 Header 名为 myHeader,不过这个 Header 有两个值。此时我们执行请求,会发现返回的结果并不能将这两个值如数返回。结果示例如下:

    {myheader=h1, host=localhost:8080, connection=Keep-Alive, user-agent=Apache-HttpClient/4.5.12 (Java/11.0.6), accept-encoding=gzip,deflate}

案例解析

  • 实际上,当我们看到这个测试结果,大多数同学已经能反应过来了。对于一个多值的 Header,在实践中,通常有两种方式来实现,一种是采用下面的方式:

    Key: value1,value2,

  • 而另外一种方式就是我们测试请求中的格式:

    Key:value1
    Key:value2

  • 对于方式 1,我们使用 Map 接口自然不成问题。但是如果使用的是方式 2,我们就不能拿到所有的值。这里我们可以翻阅代码查下 Map 是如何接收到所有请求的。

  • 对于一个 Header 的解析,主要有两种方式,分别实现在 RequestHeaderMethodArgumentResolver 和 RequestHeaderMapMethodArgumentResolver 中,它们都继承于 AbstractNamedValueMethodArgumentResolver,但是应用的场景不同,我们可以对比下它们的 supportsParameter(),来对比它们适合的场景:
    在这里插入图片描述

  • 在上图中,左边是 RequestHeaderMapMethodArgumentResolver 的方法。通过比较可以发现,对于一个标记了 @RequestHeader 的参数,如果它的类型是 Map,则使用 RequestHeaderMapMethodArgumentResolver,否则一般使用的是 RequestHeaderMethodArgumentResolver。

  • 在我们的案例中,很明显,参数类型定义为 Map,所以使用的自然是 RequestHeaderMapMethodArgumentResolver。接下来,我们继续查看它是如何解析 Header 的,关键代码参考 resolveArgument():

    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {Class<?> paramType = parameter.getParameterType();if (MultiValueMap.class.isAssignableFrom(paramType)) {MultiValueMap<String, String> result;if (HttpHeaders.class.isAssignableFrom(paramType)) {result = new HttpHeaders();}else {result = new LinkedMultiValueMap<>();}for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {String headerName = iterator.next();String[] headerValues = webRequest.getHeaderValues(headerName);if (headerValues != null) {for (String headerValue : headerValues) {result.add(headerName, headerValue);}}}return result;}else {Map<String, String> result = new LinkedHashMap<>();for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {String headerName = iterator.next();//只取了一个“值”String headerValue = webRequest.getHeader(headerName);if (headerValue != null) {result.put(headerName, headerValue);}}return result;}
    }
    
  • 针对我们的案例,这里并不是 MultiValueMap,所以我们会走入 else 分支。这个分支首先会定义一个 LinkedHashMap,然后将请求一一放置进去,并返回。其中第 29 行是去解析获取 Header 值的实际调用,在不同的容器下实现不同。例如在 Tomcat 容器下,它的执行方法参考 MimeHeaders#getValue:

    public MessageBytes getValue(String name) {for (int i = 0; i < count; i++) {if (headers[i].getName().equalsIgnoreCase(name)) {return headers[i].getValue();}}return null;
    }
    
  • 当一个请求出现多个同名 Header 时,我们只要匹配上任何一个即立马返回。所以在本案例中,只返回了一个 Header 的值。

  • 其实换一个角度思考这个问题,毕竟前面已经定义的接收类型是 LinkedHashMap,它的 Value 的泛型类型是 String,也不适合去组织多个值的情况。综上,不管是结合代码还是常识,本案例的代码都不能获取到 myHeader 的所有值。

问题修正

  • 现在我们要修正这个问题。在案例解析部分,其实已经给出了答案。

  • 在 RequestHeaderMapMethodArgumentResolver 的 resolveArgument() 中,假设我们的参数类型是 MultiValueMap,我们一般会创建一个 LinkedMultiValueMap,然后使用下面的语句来获取 Header 的值并添加到 Map 中去:String[] headerValues = webRequest.getHeaderValues(headerName)

  • 参考上面的语句,不用细究,我们也能看出,我们是可以获取多个 Header 值的。另外假设我们定义的是 HttpHeaders(也是一种 MultiValueMap),我们会直接创建一个 HttpHeaders 来存储所有的 Header。

  • HttpHeaders 来存储所有的 Header。有了上面的解析,我们可以得出这样一个结论:要完整接收到所有的 Header,不能直接使用 Map 而应该使用 MultiValueMap。我们可以采用以下两种方式来修正这个问题:

    //方式 1
    @RequestHeader() MultiValueMap map
    //方式 2
    @RequestHeader() HttpHeaders map
    
  • 重新运行测试,你会发现结果符合预期:

    [myheader:“h1”, “h2”, host:“localhost:8080”, connection:“Keep-Alive”, user-agent:“Apache-HttpClient/4.5.12 (Java/11.0.6)”, accept-encoding:“gzip,deflate”]

  • 对比来说,方式 2 更值得推荐,因为它使用了大多数人常用的 Header 获取方法,例如获取 Content-Type 直接调用它的 getContentType() 即可,诸如此类,非常好用。

关键字:小程序开发网站_湖南长沙浏阳最新疫情_百度推广有用吗_哪些浏览器可以看禁止访问的网站

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: