如何在 Spring REST Controller中读取 HTTP 请求头

https://www.baeldung.com/spring-rest-http-headers

1. 概述

在本简单教程中,我们将了解如何在 Spring Rest Controller 中访问 HTTP 请求头。

首先,我们将使用@RequestHeader 注解来单独或一起读取标头。

之后,我们将深入了解@RequestHeader 属性。

2. 访问HTTP请求头

2.1. 单独访问

如果我们需要访问特定的头,我们可以使用头名称配置@RequestHeader:

1
2
3
4
5
@GetMapping("/greeting")
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {
// 以下代码使用 language 变量
return new ResponseEntity<String>(greeting, HttpStatus.OK);
}

然后我们可以使用传递给我们的方法变量访问该值。 如果在请求中找不到名为 accept-language 的请求头,该方法将返回“400 Bad Request”错误。

请求头不必是字符串。 如果请求头是一个数字,可以将变量声明为数字类型:

1
2
3
4
5
@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. 全部一起访问

如果不确定将出现哪些请求头,或者需要的请求头比我们方法签名中定义的更多,我们可以使用没有特定名称的 @RequestHeader 注解批注。

我们有几种变量类型选择:Map、MultiValueMap 或 HttpHeaders 对象。

首先,将请求头作为 Map 获取:

1
2
3
4
5
6
7
8
9
10
@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 并且其中一个请求头具有多个值,我们将只获得第一个值。 这相当于在 MultiValueMap 上使用 getFirst 方法。

如果请求头可能有多个值,我们可以将它们作为 MultiValueMap 获取:

1
2
3
4
5
6
7
8
9
10
11
@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 对象获取:

1
2
3
4
5
6
@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);
}

HttpHeaders 对象具有用于常用应用请求头的访问器。

当通过 Map、MultiValueMap 或 HttpHeaders 对象的名称访问请求头时,如果它不存在,我们将得到一个 null。

3. @RequestHeader 属性

现在我们已经了解了使用 @RequestHeader 注解访问请求头的基础知识,接下来仔细看看它的属性。

当我们特别命名我们的请求头时,我们已经隐式地使用了 name 或 value 属性:

1
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {}

我们可以通过使用 name 属性来完成同样的事情:

1
public ResponseEntity<String> greeting(@RequestHeader(name = "accept-language") String language) {}

接下来,让我们以完全相同的方式使用 value 属性:

1
public ResponseEntity<String> greeting(@RequestHeader(value = "accept-language") String language) {}

当我们专门命名一个请求头时,该请求头将变成必填项。 如果在请求中找不到请求头,控制器将返回 400 错误。

可以使用 required 属性来表明请求头不是必需的:

1
2
3
4
5
6
7
@GetMapping("/nonRequiredHeader")
public ResponseEntity<String> evaluateNonRequiredHeader(
@RequestHeader(value = "optional-header", required = false) String optionalHeader) {
return new ResponseEntity<String>(String.format(
"Was the optional header present? %s!",
(optionalHeader == null ? "No" : "Yes")),HttpStatus.OK);
}

由于如果请求中不存在目标请求头,我们的变量将为空,因此我们需要确保进行适当的空检查。

让我们使用 defaultValue 属性为我们的标头提供一个默认值:

1
2
3
4
5
6
@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);
}

4. 结论

在这个简短的教程中,我们学习了如何在 Spring REST 控制器中访问请求标头。

首先,我们使用 @RequestHeader 注解为我们的控制器方法提供请求头。

在检查了基础知识后,我们详细查看了 @RequestHeader 注释的属性。

示例代码可在 GitHub 上找到