1. 前言
在本文中,我们将学习几种在Spring Rest Controller中读取HTTP请求头(HTT Headers)的方法。
首先,我们学习使用@RequestHeader
读取一个或者全部请求头,然后我们再深入学习@RequestHeader
注解的一些常用属性。
2. 读取HTTP请求头
2.1 读取单个请求头
如果我们需要读取一个特定的请求头,我们可以使用@RequestHeader
注解并指定要读取的请求头名称:
@GetMapping("/greeting")
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {
// code that uses the language variable
return new ResponseEntity<String>(greeting, HttpStatus.OK);
}
然后我们就可以使用参数变量language
访问请求头accept-language
的内容了。如果HTTP请求中不存在该请求头,则会返回400 Bad Request
错误。
此外我们的header也可以为字符串之外的其它类型。例如,如果我们知道请求头中存放的是数字,则可以将变量声明为int
类型:
@GetMapping("/double")
public ResponseEntity<String> doubleNumber(@RequestHeader("my-number") int myNumber) {
return new ResponseEntity<String>(String.format("%d * 2 = %d",
myNumber, (myNumber * 2)), HttpStatus.OK);
}
2.2 一次获取全部的请求头
如果我们希望获取全部的HTTP请求头,我们可以不给@RequestHeader
注解指定请求头的名称。
此时,方法中与请求头绑定的参数类型可以是:Map、MultiValueMap 、HttpHeaders 。
首先,我们来看一下把所有HTTP请求头绑定为Map
类型(Key是请求头的名称,键是对应的值):
@GetMapping("/listHeaders")
public ResponseEntity<String> listAllHeaders(
@RequestHeader Map<String, String> headers) {
headers.forEach((key, value) -> {
LOG.info(String.format("Header '%s' = %s", key, value));
});
return new ResponseEntity<String>(
String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}
如果同样名称的请求头在请求中出现多次,此时使用Map
类型绑定HTTP请求头则只能取到第一个值。如果我们要获取全部的值则可以使用MultiValueMap
类型绑定HTTP请求头:
@GetMapping("/multiValue")
public ResponseEntity<String> multiValue(
@RequestHeader MultiValueMap<String, String> headers) {
headers.forEach((key, value) -> {
LOG.info(String.format(
"Header '%s' = %s", key, value.stream().collect(Collectors.joining("|"))));
});
return new ResponseEntity<String>(
String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}
我们也可以使用HttpHeaders
对象来绑定请求头:
@GetMapping("/getBaseUrl")
public ResponseEntity<String> getBaseUrl(@RequestHeader HttpHeaders headers) {
InetSocketAddress host = headers.getHost();
String url = "http://" + host.getHostName() + ":" + host.getPort();
return new ResponseEntity<String>(String.format("Base URL = %s", url), HttpStatus.OK);
}
3. @RequestHeader的属性
现在我们已经学习了@RequestHeader
注解,下面我们研究一下它的一些属性。
属性value
与name
是等价的,这意味着下面的三段代码可以实现一样的功能:
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {}
public ResponseEntity<String> greeting(
@RequestHeader(name = "accept-language") String language) {}
public ResponseEntity<String> greeting(
@RequestHeader(value = "accept-language") String language) {}
默认情况下,如果给@RequestHeader
注解指定了具体的请求头名称,但是HTTP请求中却没有找到该请求头,则会抛出400错误。
我们可以把required
属性设为false,这样当HTTP请求中该请求头不存在时就不会抛出400错误(但是会把值设为null):
@GetMapping("/nonRequiredHeader")
public ResponseEntity<String> evaluateNonRequiredHeader(
@RequestHeader(value = "optional-header", required = false) String optionalHeader) {
// 检测optionalHeader是否为null,null即表示HTTP请求中不存在该请求头
return new ResponseEntity<String>(String.format(
"Was the optional header present? %s!",
(optionalHeader == null ? "No" : "Yes")),HttpStatus.OK);
}
我们还可以使用defaultValue
属性,给该请求头一个默认值,如果HTTP请求中没找到该请求头则使用默认值:
@GetMapping("/default")
public ResponseEntity<String> evaluateDefaultHeaderValue(
@RequestHeader(value = "optional-header", defaultValue = "3600") int optionalHeader) {
return new ResponseEntity<String>(
String.format("Optional Header is %d", optionalHeader), HttpStatus.OK);
}