问题
I'm developing Spring Boot v2.2.2.RELEASE and API versioning using Custom Header. By default I want latest version of endpoint to be executed.
Here in below code its X-API-VERSION=2
. Before executing the endpoint I need to check mapping and then set the latest version in for the Custom Header and then execute it.
@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();
}
回答1:
If I got your question right, you want that the request sent without X-API-VERSION
header will automatically be routed to headerV2()
method
This can be done:
Conceptually you'll need a Web Filter that gets executed before the Spring MVC Dispatch Servlet and you'll have to check whether the request contains a header and if it doesn't add a header of the version that you think should be the latest one (from configuration or something).
One caveat here is that the HttpServletRequest doesn't allow adding Headers so you'll have to create a HttpServletRequestWrapper and implement the logic of header addition there.
Here is an example (I've borrowed the implementation from 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";
}
}
Note that the request is wrapped to add the header as I've explained:
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);
}
}
With this implementation (make sure you put the servlet in the package next to controller or something so that the spring boot will recognize it as a component) you'll see:
- GET with header
X-API-VERSION=1
will be routed toheaderV1()
- GET with header
X-API-VERSION=2
will be routed toheaderV2()
- GET without
X-API-VERSION
header will be routed toheaderV2()
回答2:
You can add default method without header, like that:
@GetMapping(value = "/student/header")
public StudentV1 headerDefault() {
return headerV2();
}
Or just remove headers = {"X-API-VERSION=2"}
from method that should be current.
来源:https://stackoverflow.com/questions/60144816/how-to-by-default-execute-the-latest-version-of-endpoint-in-spring-boot-rest