URL 的长度有限,所能携带的信息也因此受到了制约,如果想提供更多的信息,Header 往往是不二之举
例如 Content-Type 指定了我们的请求或者响应的内容类型,便于我们去做解码。
1.接受 Header 使用错 Map 类型
解析header的常见做法:
@RequestMapping(path = "/hi", method = RequestMethod.GET)
public String hi(@RequestHeader("myHeaderName") String name){
//省略 body 处理
};
// 当header信息较多时可以如下方式
@RequestMapping(path = "/hi1", method = RequestMethod.GET)
public String hi1(@RequestHeader() Map map){
return map.toString();
};
当header中,一个key有多个值时就不符合我们需求了
Key: value1,value2
Key:value1
Key:value2
源码中执行:HandlerMethodArgumentResolver#resolveArgument方法进行参数的解析
修正:
//方式 1
@RequestHeader() MultiValueMap map
//方式 2
@RequestHeader() HttpHeaders map
2.错认为 Header 名称首字母可以一直忽略大小写
在 HTTP 协议中,Header 的名称是无所谓大小写的
@RequestMapping(path = "/hi2", method = RequestMethod.GET)
public String hi2(@RequestHeader("MyHeader") String myHeader){
return myHeader;
};
// 当我们从MultiValueMap获取header的值无法忽略大小写获取值
@RequestMapping(path = "/hi2", method = RequestMethod.GET)
public String hi2(@RequestHeader("MyHeader") String myHeader, @RequestHeader MultiValueMap map){
return myHeader + " compare with : " + map.get("MyHeader");
};
源码解析:RequestHeaderMethodArgumentResolver#resolveName
- 存取 Map 的 Header 是没有忽略大小写的
- 从 Map 中获取的 Header 也没有忽略大小写
- 从HttpHeaders map中获取key是忽略大小写的
在实际使用时,虽然 HTTP 协议规范可以忽略大小写,但是不是所有框架提供的接口方法都是可以忽略大小写的
3.试图在 Controller 中随意自定义 CONTENT_TYPE
@RequestMapping(path = "/hi3", method = RequestMethod.GET)
public String hi3(HttpServletResponse httpServletResponse){
httpServletResponse.addHeader("myheader", "myheadervalue");
httpServletResponse.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
return "ok";
};
虽然我们在 Controller 设置了 Content-Type,但是它是一种特殊的 Header,所以在 Spring Boot 基于内嵌 Tomcat 开发时并不一定能设置成功,最终返回的 Content-Type 是根据实际的返回值及类型等多个因素来决定的
修正:
- 修改请求中的 Accept 头,约束返回类型。带上 Accept 头,这样服务器在最终决定 MediaType 时,会选择 Accept 的值。具体执行可参考方法 AbstractMessageConverterMethodProcessor#getAcceptableMediaTypes
- 标记返回类型
@RequestMapping(path = "/hi3", method = RequestMethod.GET, produces = {"application/json"})
使用 produces 属性来指明即可。这样的方式影响的是可以返回的 Media 类型,一旦设置,下面的方法就可以只返回一个指明的类型了。参考 AbstractMessageConverterMethodProcessor#getProducibleMediaTypes