如何在Spring REST控制器中读取HTTP标头

2023/05/19

1. 概述

在本教程中,我们介绍如何在Spring Rest Controller中访问HTTP请求头。

首先,我们使用@RequestHeader来单独读取请求头以及读取一组请求头。

之后,我们更深入地介绍@RequestHeader中的属性。

2. 访问HTTP头

2.1 访问单个

如果需要访问特定的http请求头,我们可以使用@RequestHeader注解,并指定请求头的名字

@RestController
public class ReadHeaderRestController {

    @GetMapping("/greeting")
    public ResponseEntity<String> greeting(@RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String language) {
        // code that uses the language variable
        return new ResponseEntity<String>(greeting, HttpStatus.OK);
    }
}

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

指定的请求头不必是字符串,如果我们知道请求头是一个数字,我们可以将变量声明为int类型:

public class ReadHeaderRestController {

    @GetMapping("/double")
    public ResponseEntity<String> doubleNumber(@RequestHeader("my-number") int myNumber) {
        return new ResponseEntity<>(String.format("%d * 2 = %d", myNumber, (myNumber * 2)), HttpStatus.OK);
    }
}

2.2 访问全部

如果我们不确定包含哪些请求头,或者我们需要访问很多的请求头,我们可以使用@RequestHeader注解,而不需要指定名称。

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

首先,我们以Map的形式获取请求头:

public class ReadHeaderRestController {

    @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.format("Listed %d headers", headers.size()), HttpStatus.OK);
    }
}

如果我们使用Map并且其中一个请求头有多个值,那么我们只能得到第一个值。 这相当于在MultiValueMap上调用getFirst方法。

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

public class ReadHeaderRestController {

    @GetMapping("/multiValue")
    public ResponseEntity<String> multiValue(@RequestHeader MultiValueMap<String, String> headers) {
        headers.forEach((key, value) -> LOG.info(String.format("Header '%s' = %s", key, String.join("|", value))));

        return new ResponseEntity<>(String.format("Listed %d headers", headers.size()), HttpStatus.OK);
    }
}

我们还可以将请求头作为HttpHeaders对象获取:

public class ReadHeaderRestController {

    @GetMapping("/getBaseUrl")
    public ResponseEntity<String> getBaseUrl(@RequestHeader HttpHeaders headers) {
        InetSocketAddress host = headers.getHost();
        String url = "http://" + host.getHostName() + ":" + host.getPort();
        return new ResponseEntity<>(String.format("Base URL = %s", url), HttpStatus.OK);
    }
}

HttpHeaders对象具有通用应用程序请求头的访问器。

当我们从Map、MultiValueMap或HttpHeaders对象中按名称访问请求头时,如果它不存在,我们将得到一个null值

3. @RequestHeader属性

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

/*@formatter:off*/
public ResponseEntity<String> greeting(@RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String language) {
}
/*@formatter:on*/

我们可以通过明确指定name属性来实现相同的效果:

/*@formatter:off*/
public ResponseEntity<String> greeting(@RequestHeader(name = HttpHeaders.ACCEPT_LANGUAGE) String language) {
}
/*@formatter:on*/

对于value属性也一样:

/*@formatter:off*/
public ResponseEntity<String> greeting(@RequestHeader(value = HttpHeaders.ACCEPT_LANGUAGE) String language) {
}
/*@formatter:on*/

当我们指定了请求头的名字时,默认情况下请求头是必需的。如果在请求中找不到该请求头,则控制器返回400错误。

通过使用required属性,我们可以指定请求头不是必需存在请求中的:

public class ReadHeaderRestController {

    @GetMapping("/nonRequiredHeader")
    public ResponseEntity<String> evaluateNonRequiredHeader(@RequestHeader(value = "optional-header", required = false) String optionalHeader) {

        return new ResponseEntity<>(
                String.format("Was the optional header present? %s!", (optionalHeader == null ? "No" : "Yes")),
                HttpStatus.OK);
    }
}

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

通过使用defaultValue属性,我们可以为请求头提供默认值:

public class ReadHeaderRestController {

    @GetMapping("/default")
    public ResponseEntity<String> evaluateDefaultHeaderValue(@RequestHeader(value = "optional-header", defaultValue = "3600") int optionalHeader) {

        return new ResponseEntity<>(String.format("Optional Header is %d", optionalHeader), HttpStatus.OK);
    }
}

4. 总结

在这个教程中,我们介绍了如何访问Spring REST控制器中的请求头。

首先,我们使用@RequestHeader注解来指定我们需要获取的请求头,然后我们详细介绍了@RequestHeader注解包含的属性。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章