Spring MVC @RestController 和重定向
Spring MVC @RestController and redirect
我有一个使用 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");
}
}
如果你 @RestController returns 一个 String 你可以使用这样的东西
return "redirect:/other/controller/";
并且这种重定向仅适用于 GET 请求,如果您想使用其他类型的请求,请使用 HttpServletResponse
为了避免对 HttpServletRequest
或 HttpServletResponse
的任何直接依赖,我建议 "pure Spring" 实现返回 ResponseEntity,如下所示:
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(newUrl));
return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
如果您的方法总是 returns 重定向,请使用 ResponseEntity<Void>
,否则通常作为通用类型返回。
遇到这个问题并对 no-one 提到 RedirectView 感到惊讶。我刚刚对其进行了测试,您可以通过以下方式以 100% spring 的方式彻底解决此问题:
@RestController
public class FooController {
@RequestMapping("/foo")
public RedirectView handleFoo() {
return new RedirectView("some-url");
}
}
redirect
表示http代码302
,在springMVC中表示Found
。
这是一个 util 方法,可以放在某种 BaseController
:
protected ResponseEntity found(HttpServletResponse response, String url) throws IOException { // 302, found, redirect,
response.sendRedirect(url);
return null;
}
但有时可能想用returnhttp代码301
代替,意思是moved permanently
.
在那种情况下,这里是 util 方法:
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
);
}
}
我的例外情况 class:
@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);
我有一个使用 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");
}
}
如果你 @RestController returns 一个 String 你可以使用这样的东西
return "redirect:/other/controller/";
并且这种重定向仅适用于 GET 请求,如果您想使用其他类型的请求,请使用 HttpServletResponse
为了避免对 HttpServletRequest
或 HttpServletResponse
的任何直接依赖,我建议 "pure Spring" 实现返回 ResponseEntity,如下所示:
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(newUrl));
return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
如果您的方法总是 returns 重定向,请使用 ResponseEntity<Void>
,否则通常作为通用类型返回。
遇到这个问题并对 no-one 提到 RedirectView 感到惊讶。我刚刚对其进行了测试,您可以通过以下方式以 100% spring 的方式彻底解决此问题:
@RestController
public class FooController {
@RequestMapping("/foo")
public RedirectView handleFoo() {
return new RedirectView("some-url");
}
}
redirect
表示http代码302
,在springMVC中表示Found
。
这是一个 util 方法,可以放在某种 BaseController
:
protected ResponseEntity found(HttpServletResponse response, String url) throws IOException { // 302, found, redirect,
response.sendRedirect(url);
return null;
}
但有时可能想用returnhttp代码301
代替,意思是moved permanently
.
在那种情况下,这里是 util 方法:
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
);
}
}
我的例外情况 class:
@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);