知識庫 / Spring / Spring Web RSS 訂閱

從請求中提取自定義標頭

Spring Web
HongKong
9
11:46 AM · Dec 06 ,2025

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 如何允許我們從所有傳入的請求中提取頭信息,並提供了一個更通用的解決方案。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.