【问题标题】:Spring MVC @RestController and redirectSpring MVC @RestController 和重定向
【发布时间】:2015-05-19 01:36:52
【问题描述】:

我有一个使用 Spring MVC @RestController 实现的 REST 端点。有时,取决于我的控制器中的输入参数,我需要在客户端发送 http 重定向。

Spring MVC @RestController 是否可以,如果可以,您能否举个例子?

【问题讨论】:

标签: spring rest spring-mvc redirect http-redirect


【解决方案1】:

由于通常需要在不直接的路径中进行重定向,我认为抛出异常并稍后处理是我最喜欢的解决方案。

使用 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);

【讨论】:

    【解决方案2】:

    redirect表示http代码302,在springMVC中表示Found

    这是一个 util 方法,可以放在某种BaseController

    protected ResponseEntity found(HttpServletResponse response, String url) throws IOException { // 302, found, redirect,
        response.sendRedirect(url);
        return null;
    }
    

    但有时可能希望返回 http 代码 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();
    }
    

    【讨论】:

      【解决方案3】:

      遇到这个问题,很惊讶没有人提到 RedirectView。我刚刚对其进行了测试,您可以通过以下方式以干净的 100% 弹簧方式解决此问题:

      @RestController
      public class FooController {
      
          @RequestMapping("/foo")
          public RedirectView handleFoo() {
              return new RedirectView("some-url");
          }
      }
      

      【讨论】:

      • 知道如何使用上下文路径设置 url 吗?
      • @Bahij.Mik 我假设您在询问 servlet 上下文路径——下面告诉我您可以自动装配 servlet 上下文并从中检索路径link
      【解决方案4】:

      为避免对HttpServletRequestHttpServletResponse 的任何直接依赖,我建议使用“纯Spring”实现返回ResponseEntity,如下所示:

      HttpHeaders headers = new HttpHeaders();
      headers.setLocation(URI.create(newUrl));
      return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
      

      如果您的方法总是返回重定向,请使用ResponseEntity&lt;Void&gt;,否则通常作为泛型类型返回。

      【讨论】:

      • 或者一行return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, newUrl).build();
      • 在这种情况下,newUrl 是否必须是完全限定的 URL?如果是这样,当重定向到您的应用程序中的另一个 URL 时,这个解决方案充其量是笨拙的,因为您必须构建整个 URL。使用 HttpServletResponse 允许您发送相对于 servlet 容器根目录的重定向。
      • 如果您使用 swagger 客户端生成代码,它就像一个魅力 ;-)
      • 我正在尝试在其中添加一个自定义标题以及“位置”,但它没有任何想法? @Arne
      【解决方案5】:

      HttpServletResponse 参数添加到您的处理程序方法,然后调用response.sendRedirect("some-url");

      类似:

      @RestController
      public class FooController {
      
        @RequestMapping("/foo")
        void handleFoo(HttpServletResponse response) throws IOException {
          response.sendRedirect("some-url");
        }
      
      }
      

      【讨论】:

      • 遗憾的是,这看起来是唯一的解决方案。我也希望没有 HttpServletResponse 参数有更好的方法。
      • @MajidLaissi - 实际上,这很可悲。在大多数情况下,完全可以将 Spring MVC 控制器从对 HTTP 作为传输协议的任何依赖中完全抽象出来,但不幸的是,这在此处是不可能的。
      • 我喜欢这个解决方案和@Arne Burmeister 的解决方案,但它们都没有解决我的浏览器问题,即由于提到的原因here
      • 这是302,返回301怎么样?
      • 有,而不是 @RestController 使用 @Controller 和返回 String 的方法作为您的模板 f.i. return "redirect:/mytemplate"
      【解决方案6】:

      如果你 @RestController 返回一个 String 你可以使用类似这样的东西

      return "redirect:/other/controller/";
      

      这种重定向只针对GET请求,如果你想使用其他类型的请求使用HttpServletResponse

      【讨论】:

      • 它仅适用于@Controller,但不适用于@RestController,它是@Controller 的专用版本,并添加@ResponseBody 注释。 Spring Framework 会自动转换返回值并写入 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 中它只会返回字符串“redirect:/other/controller”,它不会重定向
      猜你喜欢
      • 1970-01-01
      • 2014-02-23
      • 2014-06-20
      • 2015-06-05
      • 1970-01-01
      • 2018-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多