我有一个使用Spring MVC @RestController实现的REST端点。有时,根据控制器中的输入参数,我需要向客户端发送http重定向。
请问使用Spring MVC @RestController是否可以实现此功能?如果可以,请给出一个示例。
我有一个使用Spring MVC @RestController实现的REST端点。有时,根据控制器中的输入参数,我需要向客户端发送http重定向。
请问使用Spring MVC @RestController是否可以实现此功能?如果可以,请给出一个示例。
在您的处理器方法中添加一个HttpServletResponse
参数,然后调用response.sendRedirect("some-url");
类似这样:
@RestController
public class FooController {
@RequestMapping("/foo")
void handleFoo(HttpServletResponse response) throws IOException {
response.sendRedirect("some-url");
}
}
为了避免直接依赖于HttpServletRequest
或HttpServletResponse
,我建议使用“纯Spring”实现,返回一个ResponseEntity,像这样:
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(newUrl));
return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
如果你的方法总是返回一个重定向,使用 ResponseEntity<Void>
,否则就按照通常的泛型类型返回。
return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, newUrl).build();
- Johannes Flügel看到这个问题,很惊讶没有人提到 RedirectView。我刚刚测试过,您可以使用以下方式以清洁的100% Spring 方式解决此问题:
@RestController
public class FooController {
@RequestMapping("/foo")
public RedirectView handleFoo() {
return new RedirectView("some-url");
}
}
redirect
意味着 http 状态码 302
,在 springMVC 中表示 Found
。
这里有一个实用方法,可以放在某种类型的 BaseController
中:
protected ResponseEntity found(HttpServletResponse response, String url) throws IOException { // 302, found, redirect,
response.sendRedirect(url);
return null;
}
但有时候可能希望返回 301
状态码,表示 永久移动
。
这种情况下,可以使用以下实用方法:
protected ResponseEntity movedPermanently(HttpServletResponse response, String url) { // 301, moved permanently,
return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, url).build();
}
由于重定向通常需要经过不直接的路径,我认为抛出异常并稍后处理是我最喜欢的解决方案。
使用ControllerAdvice
@ControllerAdvice
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = {
NotLoggedInException.class
})
protected ResponseEntity<Object> handleNotLoggedIn(
final NotLoggedInException ex, final WebRequest request
) {
final String bodyOfResponse = ex.getMessage();
final HttpHeaders headers = new HttpHeaders();
headers.add("Location", ex.getRedirectUri());
return handleExceptionInternal(
ex, bodyOfResponse,
headers, HttpStatus.FOUND, request
);
}
}
在我的情况下,异常类:
@Getter
public class NotLoggedInException extends RuntimeException {
private static final long serialVersionUID = -4900004519786666447L;
String redirectUri;
public NotLoggedInException(final String message, final String uri) {
super(message);
redirectUri = uri;
}
}
我是这样触发它的:
if (null == remoteUser)
throw new NotLoggedInException("please log in", LOGIN_URL);
return "redirect:/other/controller/";
这种重定向只适用于GET请求,如果您想使用其他类型的请求,请使用HttpServletResponse。
@Controller
,但不适用于特殊版本的 @Controller
,即添加了 @ResponseBody
注释的 @RestController
。Spring框架会自动将返回值转换并写入HTTP响应。例如下面的代码:@RestController
public class RedirectController {
@RequestMapping("/redirect")
public String redirect() {
return "redirect:/other/controller/";
}
}
如果我们尝试访问该URL curl localhost:8080/redirect
,我们将只看到 redirect:/other/controller/
作为结果。 - Anton Balaniuc
@RestController
类,因为它包含了@ResponseBody
。你的"redirect:"字符串将不会被解释为视图。 - Jan