Spring 发布后重定向与获取后重定向
我在做一个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
@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);
}
});