Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 发布后重定向与获取后重定向_Spring_Http_Spring Mvc - Fatal编程技术网

Spring 发布后重定向与获取后重定向

Spring 发布后重定向与获取后重定向,spring,http,spring-mvc,Spring,Http,Spring Mvc,我在做一个Spring项目。这是我的基本控制器: @Controller public class Editor { private static final String EDITOR_URL = "/editor"; @RequestMapping(value = EDITOR_URL, method = {POST, GET}) public ModelAndView edit(HttpServletResponse response, HttpServletReque

我在做一个Spring项目。这是我的基本控制器:

@Controller
public class Editor {

private static final String EDITOR_URL = "/editor";

@RequestMapping(value = EDITOR_URL, method = {POST, GET})
public ModelAndView edit(HttpServletResponse response,
        HttpServletRequest request,
        RedirectAttributes redirectAttributes, 
        @RequestParam Map<String, String> allRequestParams) {

    // The code is trimmed to keep it short
    // It doesn't really matter where it gets the URL, it works fine
    String redirectURL = getRedirectUrl();
    // redirectURL is going to be /editor/pad.html
    return new ModelAndView("redirect:" + redirectUrl);
}

我试着将应用程序调试到DispatcherServlet,奇怪的是,使用GET,在302/redirect响应之后,再次调用Dispatcher并将其转换为200-不知道如何以及为什么。

我将尝试解释发生了什么,然后提供解决方案

首先,让我们忘记您正在运行rest用例,并假设请求来自浏览器

场景1:浏览器发出GET请求,服务器响应重定向。

在这种情况下,浏览器将响应状态代码读取为
302
,并使用
位置
响应头发出另一个请求。用户看到快速重新加载,但没有注意到任何错误

场景2:浏览器发出POST请求,服务器响应重定向。

在这种情况下,浏览器确实遵循响应代码并发出重定向,但是,第二个请求是GET请求,并且原始请求正文在第二个请求中丢失。这是因为严格按照HTTP标准,浏览器无法在没有用户明确请求的情况下将数据“重新发布”到服务器。(某些浏览器会提示用户并询问他们是否要重新发布)

现在,在您的代码中,
restemplate
正在使用我认为是默认的
HttpClientFactory
,很可能是这样的:

RestTemplate就是这样处理上述两种情况的:

场景1:Rest模板发出GET请求,服务器响应重定向。 在这里,Rest模板实例将完全像浏览器一样工作。这就是为什么会有两个请求,第二个请求是查找
/edm/editor/pad.html

场景2:Rest模板发出POST请求,服务器响应重定向。
在这种情况下,Rest模板将在第一次调用后停止,因为它无法自动覆盖您的请求方法并将其更改为
GET
,也无法像浏览器那样提示您获得权限

解决方案:在创建
RestTemplate
的实例时,向其传递客户端工厂的重写版本,如

new RestTemplate(new SimpleClientHttpRequestFactory() {
     protected void prepareConnection(HttpURLConnection conn, String httpMethod) throws IOException { 
       super.prepareConnection(conn, httpMethod);    
       conn.setInstanceFollowRedirects(false); 
     } 
});
这将指示rest模板在第一个请求后停止


很抱歉回答得太长,但我希望这能澄清问题。

这不是一个答案,但合理的做法是编辑始终是一篇文章。@Nathanhughs如果你认为它是一个实际的文档编辑,那么你是对的-也许命名不是最好的。但是,在从另一个服务重定向后会调用“/editor”(实际上它不会在任何地方应用任何更改/编辑),因此它必须是一个get。
@Test
public void redirectToEditPadSuccess() throws Exception {

    HttpHeaders requestHeaders = new HttpHeaders();

    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(END_POINT + "/edm/editor")
            .queryParam("param1", "val1")
            .queryParam("param2", "val2");

    HttpEntity<?> entity = new HttpEntity<>(requestHeaders);

    HttpEntity<String> response = restTemplate.exchange(
            builder.build().encode().toUri(),
            HttpMethod.POST,
            entity,
            String.class);

    HttpHeaders httpResponseHeaders = response.getHeaders();

    List<String> httpReponseLocationHeader = httpResponseHeaders.get("Location");
    assertTrue(httpReponseLocationHeader.size() == 1);

    String redirectLocation = httpReponseLocationHeader.get(0);
    URL redirectURL = new URL(redirectLocation);

    assertEquals("/edm/editor/pad.html", redirectURL.getPath());

}
WARN  org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/edm/editor/pad.html] in DispatcherServlet with name 'edm'
new RestTemplate(new SimpleClientHttpRequestFactory() {
     protected void prepareConnection(HttpURLConnection conn, String httpMethod) throws IOException { 
       super.prepareConnection(conn, httpMethod);    
       conn.setInstanceFollowRedirects(false); 
     } 
});