1. 概述
在本簡短教程中,我們將探索各種提取 Spring 應用請求頭的方法。我們將學習如何針對特定端點進行提取,之後我們將創建一個 HandlerInterceptor ,該攔截器可以攔截所有傳入的請求並提取頭部信息。
2. 使用 <em >HttpServletRequest</em ></>
為了能夠訪問有關 HTTP 請求的信息,我們可以將 `HttpServletRequest>` 對象聲明為我們端點的參數。 這允許我們查看路徑、查詢參數、cookie 和標頭等詳細信息。
例如,我們可以使用 `HttpServletRequest>` 來提取自定義標頭,當收到請求時。 要訪問特定的標頭,可以使用 `getHeader()` 方法,並指定標頭的鍵:
@RestController
public class FooBarController {
@GetMapping("foo")
public String foo(HttpServletRequest request) {
String operator = request.getHeader("operator");
return "hello, " + operator;
}
}我們可以使用 MockMvc 發送包含自定義頭部的 GET 請求。如果我們將 operator 頭設置成 “John.Doe”,我們期望響應為 “hello, John.Doe”:
@Test
public void givenARequestWithOperatorHeader_whenWeCallFooEndpoint_thenOperatorIsExtracted() throws Exception {
MockHttpServletResponse response = this.mockMvc.perform(get("/foo").header("operator", "John.Doe"))
.andDo(print())
.andReturn()
.getResponse();
assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe");
}不過,如果我們只需要請求中一個特定的頭部信息,將整個 HttpServletRequest 聲明為參數可能被視為違反 SOLID 原則中的“I”——接口隔離原則。
3. 使用 @RequestHeader
另一種訪問特定端點請求頭的方法是使用 @RequestHeader 註解:
@GetMapping("bar")
public String bar(@RequestHeader("operator") String operator) {
return "hello, " + operator;
}因此,我們的代碼不再與整個 HttpServletRequest 對象耦合,並且我們的方法現在使用所有通過參數傳入的數據。
讓我們為這個端點編寫類似的測試,並期望得到相同的結果:
@Test
public void givenARequestWithOperatorHeader_whenWeCallBarEndpoint_thenOperatorIsExtracted() throws Exception {
MockHttpServletResponse response = this.mockMvc.perform(get("/bar").header("operator", "John.Doe"))
.andDo(print())
.andReturn()
.getResponse();
assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe");
}4. 使用 HandlerInterceptor 對象
對於更復雜的用例,我們可以使用 HandlerInterceptor 對象。 它的優勢在於可以攔截所有傳入的請求並提取請求頭的值。
此外,我們可以將請求頭的值封裝在一個具有 request 作用域的 Spring Bean 中,並將其注入到可能需要的不同組件中。
首先,我們將操作符名稱封裝到一個對象中:
public class OperatorHolder {
private String operator;
// getter and setter
}現在,我們使用 @Bean 聲明它為一個 Bean。由於操作符可能在不同請求之間有所不同,因此我們應該將 Bean 的作用域設置為 SCOPE_REQUEST:
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public OperatorHolder operatorHolder() {
return new OperatorHolder();
}之後,我們需要創建一個自定義的 HandlerInterceptor 接口實現,並覆蓋 preHandle() 方法:
public class OperatorInterceptor implements HandlerInterceptor {
private final OperatorHolder operatorHolder;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String operator = request.getHeader("operator");
operatorHolder.setOperator(operator);
return true;
}
// constructor
}因此,請求被攔截,提取操作符標頭,並更新 OperatorHolder Bean。
最後,我們需要將自定義攔截器添加到 Spring MVC 的 InterceptorRegistry 中。可以通過實現 WebMvcConfigurer 並覆蓋 addInterceptor() 的配置類來實現。
@Configuration
public class HeaderInterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(operatorInterceptor());
}
@Bean
public OperatorInterceptor operatorInterceptor() {
return new OperatorInterceptor(operatorHolder());
}
}為了現在訪問操作員,我們只需要注入 OperatorHolder Bean 並調用 getOperator() 方法:
@RestController
public class BuzzController {
private final OperatorHolder operatorHolder;
@GetMapping("buzz")
public String buzz() {
return "hello, " + operatorHolder.getOperator();
}
// constructor
}5. 結論
在本文中,我們探討了訪問自定義 HTTP 請求頭的方法。
最初,我們學習瞭如何通過 HttpServletRequest 和 @RequestHeader 來針對特定端點進行操作。隨後,我們看到了 HandlerInterceptor 如何允許我們從所有傳入的請求中提取頭信息,並提供了一個更通用的解決方案。