max*_*yme 3 spring url-rewriting http-status-code-301 spring-boot request-mapping
假设我有以下控制器及其父类:
@RestController
public class BusinessController extends RootController {
@GetMapping(value = "users", produces = {"application/json"})
@ResponseBody
public String users() {
return "{ \"users\": [] }"
}
@GetMapping(value = "companies", produces = {"application/json"})
@ResponseBody
public String companies() {
return "{ \"companies\": [] }"
}
}
@RestController
@RequestMapping(path = "api")
public class RootController {
}
Run Code Online (Sandbox Code Playgroud)
通过调用以下 URL 来检索数据:
http://app.company.com/api/users
http://app.company.com/api/companies
Run Code Online (Sandbox Code Playgroud)
现在假设我想重命名/api路径,但通过在新 URI 旁边/rest返回 HTTP 状态代码来保持其“可用”301
例如客户请求:
GET /api/users HTTP/1.1
Host: app.company.com
Run Code Online (Sandbox Code Playgroud)
服务器请求:
HTTP/1.1 301 Moved Permanently
Location: http://app.company.com/rest/users
Run Code Online (Sandbox Code Playgroud)
所以我计划在我的父控制器中将其更改为"api":"rest"
@RestController
@RequestMapping(path = "rest")
public class RootController {
}
Run Code Online (Sandbox Code Playgroud)
然后引入一个“遗留”控制器:
@RestController
@RequestMapping(path = "api")
public class LegacyRootController {
}
Run Code Online (Sandbox Code Playgroud)
但现在如何让它“重写”“遗留”URI?
这就是我正在努力解决的问题,无论是在 StackOverflow 还是其他地方,我都找不到任何与 Spring 相关的内容。
另外,我有很多控制器和很多方法端点,所以我无法手动执行此操作(即通过编辑每个 @RequestMapping/@GetMapping 注释)。
我正在做的项目是基于Spring Boot 2.1
编辑:我删除了/business路径,因为实际上继承在“默认情况下”不起作用(请参阅诸如Spring MVC @RequestMapping Inheritance或在启动时修改 @RequestMappings 之类的问题和解答) - 对此感到抱歉。
我终于找到了一种方法来实现这一点,既作为javax.servlet.Filter实现又作为org.springframework.web.server.WebFilter实现。
事实上,我引入适配器模式是为了转换两者:
org.springframework.http.server.ServletServerHttpResponse(非反应性)和org.springframework.http.server.reactive.ServerHttpResponse(反应性)org.springframework.http.HttpRequest因为与 Spring 的 HTTP 请求的包装器共享(让我访问URI和)相反HttpHeaders,响应的包装器不共享执行此操作的通用接口,所以我必须模拟一个(这里特意以类似的方式命名,HttpResponse) 。
@Component
public class RestRedirectWebFilter implements Filter, WebFilter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
ServletServerHttpRequest request = new ServletServerHttpRequest((HttpServletRequest) servletRequest);
ServletServerHttpResponse response = new ServletServerHttpResponse((HttpServletResponse) servletResponse);
if (actualFilter(request, adapt(response))) {
chain.doFilter(servletRequest, servletResponse);
}
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (actualFilter(exchange.getRequest(), adapt(exchange.getResponse()))) {
return chain.filter(exchange);
} else {
return Mono.empty();
}
}
/**
* Actual filtering.
*
* @param request
* @param response
* @return boolean flag specifying if filter chaining should continue.
*/
private boolean actualFilter(HttpRequest request, HttpResponse response) {
URI uri = request.getURI();
String path = uri.getPath();
if (path.startsWith("/api/")) {
String newPath = path.replaceFirst("/api/", "/rest/");
URI location = UriComponentsBuilder.fromUri(uri).replacePath(newPath).build().toUri();
response.getHeaders().setLocation(location);
response.setStatusCode(HttpStatus.MOVED_PERMANENTLY);
response.flush();
return false;
}
return true;
}
interface HttpResponse extends HttpMessage {
void setStatusCode(HttpStatus status);
void flush();
}
private HttpResponse adapt(ServletServerHttpResponse response) {
return new HttpResponse() {
public HttpHeaders getHeaders() {
return response.getHeaders();
}
public void setStatusCode(HttpStatus status) {
response.setStatusCode(status);
}
public void flush() {
response.close();
}
};
}
private HttpResponse adapt(org.springframework.http.server.reactive.ServerHttpResponse response) {
return new HttpResponse() {
public HttpHeaders getHeaders() {
return response.getHeaders();
}
public void setStatusCode(HttpStatus status) {
response.setStatusCode(status);
}
public void flush() {
response.setComplete();
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4573 次 |
| 最近记录: |