How can I prevent Spring MVC redirects from doing?

I want to process an AJAX request that updates an object. I do not need to return anything. The problem is that Spring MVC insists on sending the redirect to the same URL (apparently doing its post-redirected thing), which the browser follows closely.

How can I use the Spring MVC controller method only to complete and return something without sending a redirect? A search on the Internet leads to countless discussions on how to do a redirect, not how to avoid it.

This is the PUT request for http://localhost:9090/pex/api/testrun/f0a80b46-84b1-462a-af47-d1eadd779f59e with these headers:

 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 

The response contains the status code "302 Found", there is no body content and these headers:

 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: "*" 

Here is the server side code:

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

Here is the Javascript code that calls the AJAX call:

 $(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; } }); } 
+7
java spring spring-mvc
source share
3 answers

Spring MVC is built on top of the servlet API. Thus, any component that has access to the HttpServletResponse can theoretically use it to sendRedirect(String) or manually set the response code. (I speak theoretically because the answer has not yet been fulfilled when these calls are made.)

Typically, in a Spring MVC application, a @Controller can accept HttpServletResponse (or ServletResponse ) in the @RequestMapping method as an argument .

A HandlerInterceptor gets it three times as part of the DispatcherServlet request processing life cycle.

Any registered instance of Servlet Filter also has access to ServletResponse before (and after) Spring DispatcherServlet , since filters act in front of servlets.

Spring is trying to hide all of these dependencies with the Servlet API to simplify web server programming. Therefore, it provides other ways to redirect. They mainly depend on the types of return methods of the handler. More specifically, we care about String , View , ModelAndView and ResponseEntity .

All default cases are listed below:

When you return String , Spring will use the ViewResolver to solve the View based on the String value that identifies the view name. Spring UrlBasedViewResolver detect a redirect: prefix in String name names and treat them as an indication to send a redirect response. It will create a RedirectView (part of this is actually done in the ViewNameMethodReturnValueHandler , but UrlBasedViewResolver creates the View ), which will be responsible for doing the redirection using the HttpServletResponse .

This is an implementation detail, but most Spring default ViewResolver do this.

With View you can simply create and return a RedirectView yourself. You can also implement your own View class, which will do the same. Spring will use the appropriate HandlerMethodReturnValueHandler to process it.

With ModelAndView this is a combination of the two previous parameters, because you can specify either the name of the view or View .

With ResponseEntity it becomes more interesting as you control the entire response. That is, you can set the status code, headers, body, everything. All you have to do is set the status code to 302 and put the Location header with the URL redirection.

Finally, you have similar behavior in @ExceptionHandler methods (with similar return types), which you can also mix with @ResponseStatus and manually change the headers.

These are all basic cases, but since Spring MVC is almost completely configurable, there are other components to be aware of. These are HandlerMethodArgumentResolver , HandlerMethodReturnValueHandler , HandlerAdapter , HandlerExceptionResolver and ExceptionHandler , etc. Note that you rarely play with these and those that come with Spring do pretty much all the work.

+12
source share

So,

I took your code and created an application with it, tried to send a PUT request using the POSTMAN browser plugin and received a response, but there was no redirect. See if this works. I am attaching full classes, you can copy and directly use it in your application.

Here are the network headers:

 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 

And here is the code: Spring boot configuration

 @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

 @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> 
+3
source share

Spring recommends using templates after the redirect, but id does n’t do anything by default. In my controllers, I must explicitly end the message handling methods return "redirect:/url";

I suspect that the redirect will be performed when testrunService.updateOverview(testrunId, body); called testrunService.updateOverview(testrunId, body); .

Edit: nothing really in testrunService.updateOverview(testrunId, body); cannot cause redirection due to @ResponseBody annotation. With this code, only interceptors or filters could redirect.

+1
source share

All Articles