掘金 后端 ( ) • 2024-06-26 00:25

RequestHeaderMapMethodArgumentResolver 用于将 HTTP 请求头解析为 Map 类型参数的参数解析器。这个解析器允许开发者通过一个 Map 参数轻松访问所有的请求头信息。

类结构设计

image.png

业务案例:

开发一个 API 网关,需要记录所有传入请求的头信息,包括 User-AgentAuthorization 等,以便进行日志记录、安全检查或转发到下游服务。

1. 控制器方法使用 @RequestHeader 注解:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
public class GatewayController {

    @GetMapping("/proxy")
    public String proxyRequest(@RequestHeader Map<String, String> headers) {
        // 访问和使用请求头信息
        String userAgent = headers.get("User-Agent");
        String authorization = headers.get("Authorization");

        // 根据请求头信息进行业务逻辑处理
        // ...

        return "Request has been proxied";
    }
}

在这个控制器中,@RequestHeader 注解用于将所有请求头解析为一个 Map,其中键是请求头的名称,值是请求头的值。

2. 客户端请求:

客户端通过发送包含自定义头的 HTTP 请求来与 API 网关交互:

GET /proxy
User-Agent: MyCustomApp/1.0
Authorization: Bearer token_value

核心代码分析:

RequestHeaderMapMethodArgumentResolver 类实现了 HandlerMethodArgumentResolver 接口,用于解析 HTTP 请求头到 Map 类型的参数。以下是解析器的核心组件和它们的功能:

  1. 支持参数判断

    • supportsParameter 方法检查方法参数是否是 Map 类型,并且是否有 @RequestHeader 注解。
  2. 参数解析

    • resolveArgument 方法从请求中提取所有头信息,并填充到 Map 对象中。
  3. 处理多值头

    • 如果请求头可能有多个值,解析器将它们作为列表存储在 Map 中。
  4. 请求头获取

    • 使用 NativeWebRequest 来获取当前请求的所有头信息。

示例代码:

import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.util.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import java.util.Map;

public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
        return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
                !StringUtils.hasText(requestParam.name()));
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, NativeWebRequest webRequest)
            throws Exception {
        ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
        Map<String, String> headerMap = webRequest.getHeaders().toSingleValueMap();
        // 根据泛型类型检查,可能需要转换为多值Map
        if (resolvableType.isAssignableFrom(Map.class) &&
                resolvableType.getGeneric(0).resolve() == String.class &&
                resolvableType.getGeneric(1).resolve() == String.class) {
            return headerMap;
        }
        // 处理多值头的情况
        // ...
        return new LinkedHashMap<>(headerMap);
    }
}

总结:

  • RequestHeaderMapMethodArgumentResolver 允许开发者接收整个请求的头信息作为一个 Map 对象,简化了处理多个请求头的逻辑。
  • 它提供了一种灵活的方式来访问和使用请求头,尤其是在需要动态处理请求头时。