Java 如何防止 Spring MVC 进行重定向?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24086207/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I prevent Spring MVC from doing a redirect?
提问by Michael Borgwardt
I want to handle an AJAX request that updates an entity. I don't really need it to return anything. The problem is that Spring MVC insists on sending a redirect to the same URL (apparently doing its post-redirect-get thing), which the browser dutifully follows.
我想处理更新实体的 AJAX 请求。我真的不需要它来返回任何东西。问题是 Spring MVC 坚持将重定向发送到相同的 URL(显然是在做它的 post-redirect-get 事情),浏览器尽职尽责地遵循它。
How can I have a Spring MVC controller method just complete and return something without sending a redirect? Searching on the web only leads to countrless discussions of how to do a redirect, not how to avoid one.
如何让 Spring MVC 控制器方法在不发送重定向的情况下完成并返回某些内容?在网络上搜索只会导致关于如何进行重定向的无数讨论,而不是如何避免重定向。
It's a PUT request to http://localhost:9090/pex/api/testrun/f0a80b46-84b1-462a-af47-d1eadd779f59e
with these headers:
这是一个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
The response has status code "302 Found", no body content and these headers:
响应具有状态代码“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: "*"
Here's 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's the Javascript code that makes the AJAX call:
这是进行 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;
}
});
}
采纳答案by Sotirios Delimanolis
Spring MVC is built on top of the Servlet API. As such, any component that has access to the HttpServletResponse
can theoretically use it to sendRedirect(String)
or set the response code manually. (I say theoreticallybecause the response must not have yet been committed when those calls are made.)
Spring MVC 建立在 Servlet API 之上。因此,任何HttpServletResponse
可以访问 的组件理论上都可以使用它来sendRedirect(String)
手动设置响应代码。(我说理论上是因为在进行这些调用时必须尚未提交响应。)
Typically, in a Spring MVC application, a @Controller
can receive the HttpServletResponse
(or ServletResponse
) in a @RequestMapping
method as an argument.
通常,在 Spring MVC 应用程序中, a@Controller
可以接收方法中的HttpServletResponse
(或ServletResponse
)@RequestMapping
作为参数。
A HandlerInterceptor
receives it three times as part of the DispatcherServlet
's request handling lifecycle.
HandlerInterceptor
作为DispatcherServlet
的请求处理生命周期的一部分,A收到它三次。
Any registered Servlet Filter
instances also have access to the ServletResponse
before (and after) Spring's DispatcherServlet
since filters act before servlets.
任何注册的 ServletFilter
实例也可以访问ServletResponse
之前(和之后)Spring 的DispatcherServlet
因为过滤器在 servlet 之前起作用。
Spring tries to hide all these dependencies to the Servlet API to make programming web server easier. It therefore provides other ways to cause a redirect. These mostly depend on the supported handler method return types. More specifically, we care about String
, View
, ModelAndView
, and ResponseEntity
.
Spring 尝试将所有这些依赖项隐藏到 Servlet API 以简化 Web 服务器编程。因此,它提供了导致重定向的其他方法。这些主要取决于支持的处理程序方法返回类型。更具体地讲,我们关心的String
,View
,ModelAndView
,和ResponseEntity
。
The following are all default cases:
以下是所有默认情况:
When you return a String
, Spring will use a ViewResolver
to resolve a View
based on the String
value, which identifies the name of the view. Spring's UrlBasedViewResolver
will detect a redirect:
prefixin String
view names and consider it as an indication to send a redirect response. It will create a RedirectView
(part of this is actually done in ViewNameMethodReturnValueHandler
, but UrlBasedViewResolver
creates the View
) which will be in charge of doing the redirect with the HttpServletResponse
.
当您返回 a 时String
,Spring 将使用 a根据该值ViewResolver
解析 a View
,该String
值标识了视图的名称。SpringUrlBasedViewResolver
将检测视图名称中的redirect:
前缀,String
并将其视为发送重定向响应的指示。它将创建一个RedirectView
(其中一部分实际上是在 中完成的ViewNameMethodReturnValueHandler
,但UrlBasedViewResolver
创建了View
),它将负责使用HttpServletResponse
.
This is an implementation detail, but most of Spring's default ViewResolver
classes do this.
这是一个实现细节,但大多数 Spring 的默认ViewResolver
类都是这样做的。
With View
, you can simply create and return a RedirectView
yourself. You can also implement your own View
class that will do the same. Spring will use the appropriate HandlerMethodReturnValueHandler
to handle it.
使用View
,您可以简单地创建并返回一个RedirectView
自己。你也可以实现你自己的View
类来做同样的事情。Spring 将使用适当的HandlerMethodReturnValueHandler
来处理它。
With ModelAndView
, it's a mix of the two previous options since you can provide either a view name or a View
itself.
使用ModelAndView
,它是前两个选项的混合,因为您可以提供视图名称或视图View
本身。
With ResponseEntity
it gets more interesting since you control the whole response. That is, you can set a status code, headers, body, everything. All you need to do is therefore set the status code to 302 and put a Location
header with the URL to redirect to.
随着ResponseEntity
它变得更有趣,因为您可以控制整个响应。也就是说,您可以设置状态代码、标题、正文等所有内容。因此,您需要做的就是将状态代码设置为 302 并放置一个Location
包含要重定向到的 URL的标头。
Finally, you have similar behavior in @ExceptionHandler
methods(with similar return types) which you can also mix with @ResponseStatus
and modifying the headers manually.
最后,您在@ExceptionHandler
方法(具有相似的返回类型)中有类似的行为,您也可以@ResponseStatus
手动混合和修改标题。
These are all the basic cases, but since Spring MVC is almost completely customizable, there are other components to be aware of. These are HandlerMethodArgumentResolver
, HandlerMethodReturnValueHandler
, HandlerAdapter
, HandlerExceptionResolver
and ExceptionHandler
, and more. Note that you'll rarely play with these and those that come with Spring pretty much do the whole job.
这些都是基本情况,但由于 Spring MVC 几乎是完全可定制的,因此还有其他组件需要注意。这是HandlerMethodArgumentResolver
,HandlerMethodReturnValueHandler
,HandlerAdapter
,HandlerExceptionResolver
和ExceptionHandler
等。请注意,您很少会使用这些,而 Spring 附带的那些几乎可以完成整个工作。
回答by Serge Ballesta
Spring recommends using the post-redirect patterns but id does notdo anything by default.
In my controllers I have to explicetely end the methods dealing with posts by return "redirect:/url";
春建议使用后重定向模式,但ID不会不会做默认情况下任何东西。在我的控制器中,我必须明确结束处理帖子的方法return "redirect:/url";
I suspect the redirect to be done in the testrunService.updateOverview(testrunId, body);
call.
我怀疑要在testrunService.updateOverview(testrunId, body);
通话中完成重定向。
Edit : in reality, nothing in testrunService.updateOverview(testrunId, body);
could cause a redirect because of the @ResponseBody
annotation. With code like that, only interceptors or filters could do a redirection.
编辑:实际上,testrunService.updateOverview(testrunId, body);
由于@ResponseBody
注释,没有任何内容可能导致重定向。使用这样的代码,只有拦截器或过滤器才能进行重定向。
回答by dharam
So,
所以,
I took your code and created an application with that, tried sending a PUT request using browser plugin POSTMAN and got a response but no redirection. See if this works. I am attaching the complete classes, you can copy and directly use it in ur application.
我拿了你的代码并用它创建了一个应用程序,尝试使用浏览器插件 POSTMAN 发送 PUT 请求并得到响应但没有重定向。看看这是否有效。我附上了完整的类,您可以复制并直接在您的应用程序中使用它。
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: Configuration to boot up spring
这是代码: 启动 spring 的配置
@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
<?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>