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

时间:2014-06-06 16:04:36

标签: java spring 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 Found",没有正文内容和这些标题:

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;
            }
    });
}

3 个答案:

答案 0 :(得分:13)

Spring MVC构建于Servlet API之上。因此,任何有权访问HttpServletResponse的组件理论上都可以将其用于sendRedirect(String)或手动设置响应代码。 (我说理论上因为在进行这些调用时,响应必须尚未提交。)

通常,在Spring MVC应用程序中,@Controller可以HttpServletResponse方式接收ServletResponse(或@RequestMapping}作为argument

作为DispatcherServlet请求处理生命周期的一部分,HandlerInterceptor会收到它三次。

任何已注册的Servlet Filter实例也可以在Spring DispatcherServlet之前(及之后)访问ServletResponse,因为过滤器在servlet之前起作用。

Spring尝试将所有这些依赖项隐藏到Servlet API,以使编程Web服务器更容易。因此,它提供了导致重定向的其他方法。这些主要取决于supported handler method return types。更具体地说,我们关心StringViewModelAndViewResponseEntity

以下是所有默认情况:

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

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

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

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

使用ResponseEntity,因为您控制整个响应,它会变得更有趣。也就是说,您可以设置状态代码,标题,正文,一切。因此,您需要做的就是将状态代码设置为302并将View标头与URL重定向到。

最后,您在@ExceptionHandler methods(具有类似的返回类型)中也有类似的行为,您也可以将其与@ResponseStatus混合并手动修改标题。

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

答案 1 :(得分:3)

所以,

我拿了你的代码并用它创建了一个应用程序,尝试使用浏览器插件POSTMAN发送一个PUT请求并获得响应但没有重定向。看看这是否有效。 我附上完整的课程,你可以复制并直接在你的应用程序中使用它。

以下是网络标题:

Remote Address:::1:8080
Request URL:http://localhost:8080/test/api/testrun/hello
Request Method:PUT
Status Code:200 OK

**Request Headers**
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6,pl;q=0.4
Authorization:Basic ZWFzeWwtbWFpbi1pbnQ6cHJnc3VzZXI=
Cache-Control:no-cache
Connection:keep-alive
Content-Length:0
Content-Type:application/json
Host:localhost:8080
Origin:chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36

**Response Headers**
Cache-Control:private
Content-Length:5
Content-Type:text/plain;charset=ISO-8859-1
Date:Tue, 10 Jun 2014 10:58:50 GMT
Expires:Thu, 01 Jan 1970 05:30:00 IST
Server:Apache-Coyote/1.1
ConsoleSearchEmulationRendering

以下是代码: 启动弹簧的配置

@Configuration
@EnableWebMvc
@Profile("production")
@ComponentScan(basePackages = "com", excludeFilters = { @ComponentScan.Filter(Configuration.class) })
public class WebConfig extends WebMvcConfigurationSupport {

    @Override
    protected void configureContentNegotiation(
            ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).favorParameter(true)
                .parameterName("mediaType").ignoreAcceptHeader(true)
                .useJaf(false).defaultContentType(MediaType.APPLICATION_JSON)
                .mediaType("xml", MediaType.APPLICATION_XML)
                .mediaType("json", MediaType.APPLICATION_JSON);
    }

    @Bean(name = "viewResolver")
    public InternalResourceViewResolver viewResolver() throws Exception {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

        viewResolver.setPrefix("/jsp/");
        viewResolver.setSuffix(".jsp");

        return viewResolver;
    }
}

<强>控制器

@Controller
public class TestController {

    @RequestMapping(value = "/api/testrun/{testrunId}", method = RequestMethod.PUT, consumes = "application/json")
    @ResponseBody
    public String updateOverview(@PathVariable("testrunId") final String testrunId) {
        System.out.println(testrunId);

        return "hello";
    }
}

<强>的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>test</display-name>

    <context-param>
      <param-name>contextClass</param-name>
      <param-value>
         org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
    </context-param>
    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.WebConfig</param-value>
    </context-param>
    <context-param>
        <param-name>spring.profiles.active</param-name>
        <param-value>production</param-value>
    </context-param>
    <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
      <servlet-name>ui</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <init-param>
         <param-name>contextClass</param-name>
         <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
         </param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
      <servlet-name>ui</servlet-name>
      <url-pattern>/</url-pattern>
    </servlet-mapping> 
</web-app>

答案 2 :(得分:1)

Spring建议使用重定向后模式,但默认情况下,id 执行任何操作。 在我的控制器中,我必须通过return "redirect:/url";

彻底结束处理帖子的方法

我怀疑重定向是在testrunService.updateOverview(testrunId, body);电话中完成的。

编辑:实际上,由于testrunService.updateOverview(testrunId, body);注释,@ResponseBody中的任何内容都无法导致重定向。使用这样的代码,只有拦截器或过滤器可以进行重定向。