如何防止Spring MVC进行重定向?


问题内容

我想处理一个更新实体的AJAX请求。我真的不需要它来返回任何东西。问题在于,Spring
MVC坚持将重定向发送到相同的URL(显然是在执行其重定向后获取的操作),浏览器会忠实地遵循该重定向。

如何才能使Spring MVC控制器方法完成并返回某些内容而无需发送重定向?在网络上搜索只会导致无数关于如何进行重定向的讨论,而不是如何避免重定向的讨论。

这是http://localhost:9090/pex/api/testrun/f0a80b46-84b1-462a-af47-d1eadd779f59e带有以下标头的PUT请求:

Host: localhost:9090
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0
Accept: */*
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Length: 20
Content-Type: application/json
Referer: http://localhost:9090/pex/api/testrun/f0a80b46-84b1-462a-af47-d1eadd779f59e/visualizations/common-api?slas=lp,internal,external
X-Requested-With: XMLHttpRequest
Connection: keep-alive
Authorization: Basic xxxx

响应的状态码为“找到了302”,没有正文内容和以下标头:

Content-Language: "de"
Content-Length: "0"
Location: "http://localhost:9090/pex/api/testrun/f0a80b46-84b1-462a-af47-d1eadd779f59e"
Server: "Jetty(6.1.10)"
access-control-allow-origin: "*"

这是服务器端代码:

@RequestMapping(value = "/api/testrun/{testrunId}", method = RequestMethod.PUT, consumes = "application/json")
@ResponseBody
public Testrun updateOverview(@PathVariable("testrunId") final String testrunId, @RequestBody final String body) {
    return testrunService.updateOverview(testrunId, body);
}

这是进行AJAX调用的Javascript代码:

$(document).ready(function() {
    $("#update_name_form").submit(function (e) {
        update_testrun($("#name"));
        return false;
    });
}
function update_testrun(element) {
    var name = element.attr('name');
    var new_value = element.val().trim();
    var data = {};
    data[name] = new_value;
    $.ajax({url: config.urls.api.testrun + testrun.id,
            type: "PUT",
            contentType: "application/json",
            data: JSON.stringify(data),
            error: function(jqXHR, textStatus, errorThrown) {
                    alert(errorThrown);
            },
            success: function (data, textStatus, jqXHR) {
                    testrun.overview[name] = new_value;
            }
    });
}

问题答案:

Spring MVC建立在Servlet
API之上。因此,HttpServletResponse理论上可以访问的任何组件都可以使用它sendRedirect(String)手动设置或设置响应代码。(我说的是
理论上的 原因,因为在进行这些调用时还必须尚未做出响应。)

通常,在Spring MVC应用程序中,a
@Controller可以将方法中的HttpServletResponse(或ServletResponse@RequestMapping作为参数接收

HandlerInterceptorDispatcherServlet的请求处理生命周期中,A
收到了三次。

任何已注册的Servlet Filter实例都可以访问ServletResponseSpring的(之前和之后),DispatcherServlet因为过滤器在Servlet之前起作用。

Spring尝试将所有这些依赖项隐藏到Servlet
API中,以简化Web服务器的编程。因此,它提供了导致重定向的其他方法。这些主要取决于支持的处理程序方法的返回类型。更具体地讲,我们关心的StringViewModelAndView,和ResponseEntity

以下是所有默认情况:

当返回a时String,Spring将使用a
ViewResolverView基于String值解析a ,该值标识视图的名称。Spring
UrlBasedViewResolver会在视图名称中检测redirect:前缀String并将其视为发送重定向响应的指示。它将创建一个RedirectView(实际上是在其中完成了一部分ViewNameMethodReturnValueHandler,但UrlBasedViewResolver创建了View),它将负责使用进行重定向HttpServletResponse

这是一个实现细节,但是大多数Spring的默认ViewResolver类都这样做。

使用View,您可以轻松创建并返回RedirectView自己。您也可以实现自己的View类,该类将执行相同的操作。Spring将使用适当的方式HandlerMethodReturnValueHandler来处理它。

使用ModelAndView,它是前两个选项的混合,因为您可以提供视图名称或View本身。

有了ResponseEntity它,您可以控制整个响应,因此变得更加有趣。也就是说,您可以设置状态代码,标题,正文等所有内容。因此,您所需要做的就是将状态代码设置为302,并放置一个Location带有URL
的标头以重定向到。

最后,您在@ExceptionHandler方法中具有相似的行为(具有相似的返回类型),也可以将它们与@ResponseStatus手动混合并修改标头。

这些都是基本情况,但是由于Spring
MVC几乎可以完全自定义,因此还有其他组件需要注意。这是HandlerMethodArgumentResolverHandlerMethodReturnValueHandlerHandlerAdapterHandlerExceptionResolverExceptionHandler等。请注意,您很少会使用这些功能,而Spring附带的功能几乎可以完成整个工作。