如何在 Spring Boot REST 中默认执行最新版本的端点?

How to by default execute the latest version of endpoint in Spring Boot REST?

我正在使用自定义 Header 开发 Spring Boot v2.2。2.RELEASE 和 API 版本控制。默认情况下,我希望执行最新版本的端点。

下面的代码是 X-API-VERSION=2。在执行端点之前,我需要检查映射,然后为自定义 Header 设置最新版本,然后执行它。

@GetMapping(value = "/student/header", headers = {"X-API-VERSION=1"})
public StudentV1 headerV1() {
    return serviceImpl.headerV1();
}

@GetMapping(value = "/student/header", headers = {"X-API-VERSION=2"})
public StudentV1 headerV2() {
    return serviceImpl.headerV2();
}

你可以添加没有header的默认方法,像这样:

@GetMapping(value = "/student/header")
public StudentV1 headerDefault() {
    return headerV2();
}

或者只是从应该是当前的方法中删除 headers = {"X-API-VERSION=2"}

如果我答对了你的问题,你希望在没有 X-API-VERSION header 的情况下发送的请求将自动路由到 headerV2() 方法

可以这样做:

从概念上讲,您需要一个在 Spring MVC Dispatch Servlet 之前执行的 Web 过滤器,并且您必须检查请求是否包含 header 以及是否不添加您认为应该是最新版本的 header 版本(来自配置或其他)。

这里需要注意的是,HttpServletRequest 不允许添加 Headers,因此您必须创建一个 HttpServletRequestWrapper 并在那里实现 header 添加的逻辑。

这是一个例子(我从this question那里借用了实现):

// The web filter 
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;

@Component
@Order(1)
public class LatestVersionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        if(req.getHeader("X-API-VERSION")== null) {
            HeaderMapRequestWrapper wrappedRequest = new HeaderMapRequestWrapper(req);
            wrappedRequest.addHeader("X-API-VERSION", resolveLastVersion());
            filterChain.doFilter(wrappedRequest, servletResponse);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    private String resolveLastVersion() {
        // read from configuration or something
        return "2";
    }
}

请注意,请求已包装以添加 header,正如我所解释的:

class HeaderMapRequestWrapper extends HttpServletRequestWrapper {
        /**
         * construct a wrapper for this request
         *
         * @param request
         */
        public HeaderMapRequestWrapper(HttpServletRequest request) {
            super(request);
        }

        private Map<String, String> headerMap = new HashMap<String, String>();

        /**
         * add a header with given name and value
         *
         * @param name
         * @param value
         */
        public void addHeader(String name, String value) {
            headerMap.put(name, value);
        }

        @Override
        public String getHeader(String name) {
            String headerValue = super.getHeader(name);
            if (headerMap.containsKey(name)) {
                headerValue = headerMap.get(name);
            }
            return headerValue;
        }

        /**
         * get the Header names
         */
        @Override
        public Enumeration<String> getHeaderNames() {
            List<String> names = Collections.list(super.getHeaderNames());
            for (String name : headerMap.keySet()) {
                names.add(name);
            }
            return Collections.enumeration(names);
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            List<String> values = Collections.list(super.getHeaders(name));
            if (headerMap.containsKey(name)) {
                values.add(headerMap.get(name));
            }
            return Collections.enumeration(values);
        }

    }

使用此实现(确保将 servlet 放在控制器或其他东西旁边的包中,以便 spring 引导将其识别为组件)您将看到:

  1. GET 与 header X-API-VERSION=1 将被路由到 headerV1()
  2. GET 与 header X-API-VERSION=2 将被路由到 headerV2()
  3. 没有 X-API-VERSION 的 GET header 将被路由到 headerV2()